目录

Life in Flow

知不知,尚矣;不知知,病矣。
不知不知,殆矣。

X

设计模式

简单工厂

 由一个工厂对象决定创建出哪一种产品类的实例。
 创建型,但不属于 GOF23 种设计模式。
编码风格,不属于设计模式。

 1# 适用场景
 2* 工厂类负责创建的对象比较少
 3* 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心
 4
 5# 优点
 6* 只需要传入一个正确的参数,就可以获取你所需要的对象,无需知道其创建细节。
 7
 8# 缺点
 9* 工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则。
10* 无法形成基于继承的结构。

简单工厂

Video

1public abstract class Video {
2    public abstract void produce();
3}

JavaVideo

1public class JavaVideo extends Video {
2    @Override
3    public void produce() {
4        System.out.println("Java 开讲了!!!");
5    }
6}

PythonVideo

1public class PythonVideo extends Video {
2    @Override
3    public void produce() {
4        System.out.println("Python开讲了!!!");
5    }
6}

VideoFactory

 1public class VideoFactory {
 2
 3    /**
 4     * 重载   通过反射弥补扩展性(复杂的逻辑判断)
 5     * @param Class c
 6     * @return Video
 7     */
 8    public Video getVideo(Class c){
 9        Video video = null;
10        try {
11            video = (Video) Class.forName(c.getName()).newInstance();
12        } catch (InstantiationException e) {
13            e.printStackTrace();
14        } catch (IllegalAccessException e) {
15            e.printStackTrace();
16        } catch (ClassNotFoundException e) {
17            e.printStackTrace();
18        }
19        return video;
20    }
21
22    /**
23     * 重载   工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,违背开闭原则。
24     * @param String  type
25     * @return Video
26     */
27    public Video getVideo(String type){
28        if("java".equalsIgnoreCase(type)){
29            return new JavaVideo();
30        }else if("python".equalsIgnoreCase(type)){
31            return new PythonVideo();
32        }
33        return null;
34    }
35}

Test

 1public class Test {
 2    public static void main(String[] args) {
 3        //创建工厂
 4        VideoFactory videoFactory = new VideoFactory();
 5        //工厂根据传入的参数生产出对应的对象
 6        Video video = videoFactory.getVideo(JavaVideo.class);
 7        //Video video = videoFactory.getVideo("java");
 8        if(video == null){
 9            return;
10        }
11        //指定目标逻辑
12        video.produce();
13    }
14}

案例: JDK 的 Calendar

1private static Calendar createCalendar(TimeZone zone,
2                                           Locale aLocale){...  根据不同国家做判断}

案例: JDBC 加载启动

 1	Class.forName("com.mysql.jdbc.Driver");
 2
 3// Driver  类
 4package com.mysql.jdbc;
 5
 6public class Driver extends NonRegisteringDriver implements java.sql.Driver {
 7    public Driver() throws SQLException {
 8    }
 9	//使用静态代码块注册了驱动:这里注册的Driver 是mysql的Driver
10    static {
11        try {
12            DriverManager.registerDriver(new Driver());
13        } catch (SQLException var1) {
14            throw new RuntimeException("Can't register driver!");
15        }
16    }
17}

案例: logback 的 LoggerContext

1  public final Logger getLogger(final String name) { 
2	Logger childLogger = (Logger) loggerCache.get(name);
3  }

工厂方法

 定义一个创建对象的抽象方法,让子类通过继承来实现该抽象方法,但让实现这个接口的类来决定实例化哪个类,工厂方法让类的实例化过程推迟到子类中进行,也就是将创建对象的任务委托给不同的子类工厂
 工厂方法是为了解决同一产品等级业务抽象问题。
 创建型。

 1# 适用场景
 2* 创建对象需要大量重复的代码
 3* 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
 4* 一个类通过其子类来指定创建哪个对象
 5
 6# 优点
 7* 用户只需要关心所需产品对应的工厂,无须关心创建细节
 8* 加入新产品符合开闭原则,提高可扩展性
 9
10# 缺点
11* 类的个数容易过多,增加复杂度。(不同类型的工厂类,负责生生产不同类型的产品类)
12* 增加了系统的抽象性和理解难度

工厂方法

Video

1public abstract class Video {
2    //Java、Python 都属于同一个产品等级
3    public abstract void produce();
4
5}

VideoFactory

1public abstract class VideoFactory {
2    public abstract Video getVideo();
3}

JavaVideo

1public class JavaVideo extends Video {
2    @Override
3    public void produce() {
4        System.out.println("录制Java课程视频");
5    }
6}

JavaVideoFactory

1public class JavaVideoFactory extends VideoFactory {
2    @Override
3    public Video getVideo() {
4        return new JavaVideo();
5    }
6}

PythonVideo

1public class PythonVideo extends Video {
2    @Override
3    public void produce() {
4        System.out.println("录制Python课程视频");
5    }
6}

PythonVideoFactory

1public class PythonVideoFactory extends VideoFactory {
2    @Override
3    public Video getVideo() {
4        return new PythonVideo();
5    }
6}

Test

1public class Test {
2    public static void main(String[] args) {
3        VideoFactory videoFactory = new PythonVideoFactory();
4        VideoFactory videoFactory2 = new JavaVideoFactory();
5        //通过工厂创建具体实例
6        Video video = videoFactory.getVideo();
7        video.produce();
8    }
9}

案例: Collection 类的 iterator() 方法

1抽象方法是 Collection 类的 iterator() 方法
2具体实现工厂 ArrayList 类
3具体创建的产品的方法是  ArrayList 类的 iterator()
4抽象产品是 Iterator<E> 接口
5实际产品 Collection 的各个具体实现类 iterator() 方法 返回的 Iterator<E>

抽象工厂

 抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口。
 无须指定它们具体的类
 创建型

产品等级与产品族

 1# 适用场景
 2* 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节
 3* 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。
 4* 提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
 5
 6# 优点
 7* 具体产品在应用层代码隔离,无需关系创建细节
 8* 将一个系列的产品族统一到一起创建
 9
10# 缺点
11* 新增产品等级比较困难,规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂的接口
12* 增加了系统的抽象性和理解难度

抽象工厂

CourseFactory

1public interface CourseFactory {
2    Video getVideo();
3    Article getArticle();
4}

Video

1public abstract class Video {
2    public abstract void produce();
3
4}

Article

1public abstract class Article {
2    public abstract void produce();
3}

JavaVideo

1public class JavaVideo extends Video {
2    @Override
3    public void produce() {
4        System.out.println("录制Java课程视频");
5    }
6}

JavaArticle

1public class JavaArticle extends Article {
2    @Override
3    public void produce() {
4        System.out.println("编写Java课程手记");
5    }
6}

JavaCourseFactory

 1public class JavaCourseFactory implements CourseFactory {
 2    @Override
 3    public Video getVideo() {
 4        return new JavaVideo();
 5    }
 6
 7    @Override
 8    public Article getArticle() {
 9        return new JavaArticle();
10    }
11}

PythonVideo

1public class PythonVideo extends Video {
2    @Override
3    public void produce() {
4        System.out.println("录制Python课程视频");
5    }
6}

PythonArticle

1public class PythonArticle extends Article {
2    @Override
3    public void produce() {
4        System.out.println("编写Python课程手记");
5    }
6}

PythonCourseFactory

 1public class PythonCourseFactory implements CourseFactory {
 2    @Override
 3    public Video getVideo() {
 4        return new PythonVideo();
 5    }
 6
 7    @Override
 8    public Article getArticle() {
 9        return new PythonArticle();
10    }
11}

Test

 1public class Test {
 2    public static void main(String[] args) {
 3        //创建A产品族的工厂
 4        CourseFactory courseFactory = new JavaCourseFactory();
 5        //获取产品 A1
 6        Video video = courseFactory.getVideo();
 7        //获取产品 A2
 8        Article article = courseFactory.getArticle();
 9  
10        video.produce();//录制Java课程视频
11        article.produce();//编写Java课程手记
12    }
13}

案例:MySQL 的 Connection、MyBatis 的 SqlSessionFactory

建造者

 流程固定、顺序不固定:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
 用户只需指定需要建造的类型就可以得到它们,建造过程及细节不需要知道。
 创建型。

建造者模式和工厂模式的区别
 建造者模式更注重于方法的调用顺序,工厂模式只关注创建产品。
 建造者模式可以用于构建复杂的产品,而工厂模式创造出来的都是一样等级的产品。
 建造者模式更专注于创建产品的过程,而工厂模式只要把产品创建出来就行了。

 1# 适用场景
 2* 如果一个对象有非常复杂的内部结构(很多属性)
 3* 想把复杂对象的创建和使用分离
 4
 5# 优点
 6* 封装性好,创建和使用分离
 7* 扩展性好、建造类之间独立、一定程度上解耦
 8
 9# 缺点
10* 产生多余的Builder对象
11* 产品内部发生变化,建造者都要修改,成本较大

建造者 V1

Course

 1public class Course {
 2    private String courseName;
 3    private String coursePPT;
 4    private String courseVideo;
 5    private String courseArticle;
 6    //question & answer
 7    private String courseQA;
 8
 9    public String getCourseName() {
10        return courseName;
11    }
12
13    public void setCourseName(String courseName) {
14        this.courseName = courseName;
15    }
16
17    public String getCoursePPT() {
18        return coursePPT;
19    }
20
21    public void setCoursePPT(String coursePPT) {
22        this.coursePPT = coursePPT;
23    }
24
25    public String getCourseVideo() {
26        return courseVideo;
27    }
28
29    public void setCourseVideo(String courseVideo) {
30        this.courseVideo = courseVideo;
31    }
32
33    public String getCourseArticle() {
34        return courseArticle;
35    }
36
37    public void setCourseArticle(String courseArticle) {
38        this.courseArticle = courseArticle;
39    }
40
41    public String getCourseQA() {
42        return courseQA;
43    }
44
45    public void setCourseQA(String courseQA) {
46        this.courseQA = courseQA;
47    }
48
49    @Override
50    public String toString() {
51        return "Course{" +
52                "courseName='" + courseName + '\'' +
53                ", coursePPT='" + coursePPT + '\'' +
54                ", courseVideo='" + courseVideo + '\'' +
55                ", courseArticle='" + courseArticle + '\'' +
56                ", courseQA='" + courseQA + '\'' +
57                '}';
58    }
59}

CourseBuilder

 1public abstract class CourseBuilder {
 2
 3    public abstract void buildCourseName(String courseName);
 4    public abstract void buildCoursePPT(String coursePPT);
 5    public abstract void buildCourseVideo(String courseVideo);
 6    public abstract void buildCourseArticle(String courseArticle);
 7    public abstract void buildCourseQA(String courseQA);
 8
 9    public abstract Course makeCourse();
10}

CourseActualBuilder

 1public class CourseActualBuilder extends CourseBuilder {
 2
 3    private Course course = new Course();
 4
 5
 6    @Override
 7    public void buildCourseName(String courseName) {
 8        course.setCourseName(courseName);
 9    }
10
11    @Override
12    public void buildCoursePPT(String coursePPT) {
13        course.setCoursePPT(coursePPT);
14    }
15
16    @Override
17    public void buildCourseVideo(String courseVideo) {
18        course.setCourseVideo(courseVideo);
19    }
20
21    @Override
22    public void buildCourseArticle(String courseArticle) {
23        course.setCourseArticle(courseArticle);
24    }
25
26    @Override
27    public void buildCourseQA(String courseQA) {
28        course.setCourseQA(courseQA);
29    }
30
31    @Override
32    public Course makeCourse() {
33        return course;
34    }
35}

Coach

 1public class Coach {
 2    private CourseBuilder courseBuilder;
 3
 4    public void setCourseBuilder(CourseBuilder courseBuilder) {
 5        this.courseBuilder = courseBuilder;
 6    }
 7
 8    public Course makeCourse(String courseName,String coursePPT,
 9                             String courseVideo,String courseArticle,
10                             String courseQA){
11        this.courseBuilder.buildCourseName(courseName);
12        this.courseBuilder.buildCoursePPT(coursePPT);
13        this.courseBuilder.buildCourseVideo(courseVideo);
14        this.courseBuilder.buildCourseArticle(courseArticle);
15        this.courseBuilder.buildCourseQA(courseQA);
16        return this.courseBuilder.makeCourse();
17    }
18}

Test

 1public class Test {
 2    public static void main(String[] args) {
 3        //课程构建类
 4        CourseBuilder courseBuilder = new CourseActualBuilder();
 5        //建造者
 6        Coach coach = new Coach();
 7        coach.setCourseBuilder(courseBuilder);
 8
 9        //建造者通过课程构建类完成课程的具体构建流程
10        Course course = coach.makeCourse("Java设计模式精讲",
11                "Java设计模式精讲PPT",
12                "Java设计模式精讲视频",
13                "Java设计模式精讲手记",
14                "Java设计模式精讲问答");
15        System.out.println(course);//Course{courseName='Java设计模式精讲', coursePPT='Java设计模式精讲PPT', courseVideo='Java设计模式精讲视频', courseArticle='Java设计模式精讲手记', courseQA='Java设计模式精讲问答'}
16    }
17}

或者改进(链式调用)

建造者 V2

Course

 1public class Course {
 2
 3    private String courseName;
 4    private String coursePPT;
 5    private String courseVideo;
 6    private String courseArticle;
 7
 8    //question & answer
 9    private String courseQA;
10
11    public Course(CourseBuilder courseBuilder) {
12        this.courseName = courseBuilder.courseName;
13        this.coursePPT = courseBuilder.coursePPT;
14        this.courseVideo = courseBuilder.courseVideo;
15        this.courseArticle = courseBuilder.courseArticle;
16        this.courseQA = courseBuilder.courseQA;
17    }
18
19
20    @Override
21    public String toString() {
22        return "Course{" +
23                "courseName='" + courseName + '\'' +
24                ", coursePPT='" + coursePPT + '\'' +
25                ", courseVideo='" + courseVideo + '\'' +
26                ", courseArticle='" + courseArticle + '\'' +
27                ", courseQA='" + courseQA + '\'' +
28                '}';
29    }
30
31    public static class CourseBuilder{
32        private String courseName;
33        private String coursePPT;
34        private String courseVideo;
35        private String courseArticle;
36
37        //question & answer
38        private String courseQA;
39
40        public CourseBuilder buildCourseName(String courseName){
41            this.courseName = courseName;
42            return this;
43        }
44
45
46        public CourseBuilder buildCoursePPT(String coursePPT) {
47            this.coursePPT = coursePPT;
48            return this;
49        }
50
51        public CourseBuilder buildCourseVideo(String courseVideo) {
52            this.courseVideo = courseVideo;
53            return this;
54        }
55
56        public CourseBuilder buildCourseArticle(String courseArticle) {
57            this.courseArticle = courseArticle;
58            return this;
59        }
60
61        public CourseBuilder buildCourseQA(String courseQA) {
62            this.courseQA = courseQA;
63            return this;
64        }
65
66	/**
67         * 完成 Course 的构造
68         * @return
69         */
70        public Course build(){
71            return new Course(this);
72        }
73  
74    }
75}

Test

1public class Test {
2    public static void main(String[] args) {
3        //链式调用
4        Course course = new Course.CourseBuilder().buildCourseName("Java设计模式精讲").buildCoursePPT("Java设计模式精讲PPT").buildCourseVideo("Java设计模式精讲视频").build();
5        System.out.println(course);//Course{courseName='Java设计模式精讲', coursePPT='Java设计模式精讲PPT', courseVideo='Java设计模式精讲视频', courseArticle='null', courseQA='null'}
6
7    }
8}

案例:StringBuilder、StringBuffer、ImmutableSet(Guava)

1        Set<String> set = ImmutableSet.<String>builder().add("a").add("b").build();
2        System.out.println(set);//[a, b]

单例

 保证一个类仅有一个实例,并提供一个全局访问点。
 创建型

 1# 适用场景
 2* 想确保任何情况下都绝对只有一个实例
 3
 4# 优点
 5* 在内存里只有一个实例,减少了内存开销
 6* 可以避免对资源的多重占用
 7* 设置了全局访问点,严格控制访问
 8
 9# 缺点
10* 没有接口,扩展困难(需要修改代码)
11
12# 重点
13* 私有构造函数
14* 线程安全
15* 延迟加载
16* 序列化和反序列化安全
17* 防御反射攻击
18
19# 单例模式和其他设计模式的结合应用
20* 单例模式和工厂模式
21* 单例模式和享元模式

懒汉式(线程安全:性能太低 —— 同步方法)

 1public class LazySingleton {
 2    //初始化时不创建(延迟加载)
 3    private static LazySingleton lazySingleton = null;
 4
 5    /**
 6     * 私有化无参构造函数
 7     */
 8    private LazySingleton(){
 9    }
10
11    /**
12     * 全局访问点
13     * @return
14     */
15    public synchronized static LazySingleton getInstance(){
16        //空则创建:延迟加载
17        if(lazySingleton == null){
18            lazySingleton = new LazySingleton();
19        }
20        //非空直接返回
21        return lazySingleton;
22    }

懒汉式 (性能优化)
单例-Double Check
单例_Double Check_volatile
LazyDoubleCheckSingleton

第一种解决思路(双重检查):不允许 第二步、第三步 发生重排序

 1public class LazyDoubleCheckSingleton {
 2    //不允许:第二步、第三步 (禁止重排序)
 3    private volatile static LazyDoubleCheckSingleton lazyDoubleCheckSingleton = null;
 4    private LazyDoubleCheckSingleton(){
 5
 6    }
 7    public static LazyDoubleCheckSingleton getInstance(){
 8        if(lazyDoubleCheckSingleton == null){
 9            synchronized (LazyDoubleCheckSingleton.class){
10                if(lazyDoubleCheckSingleton == null){
11                    lazyDoubleCheckSingleton = new LazyDoubleCheckSingleton();
12                    //1.分配内存给这个对象
13                    //3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
14                    //2.初始化对象
15                    //intra-thread semantics
16                    //---------------//3.设置lazyDoubleCheckSingleton 指向刚分配的内存地址
17                }
18            }
19        }
20        return lazyDoubleCheckSingleton;
21    }
22}

第二种解决思路(静态内部类:基于类初始化的延迟加载解决方案):允许发生重排序,但是不允许其他线程看到
静态内部类:基于类初始化的延迟加载解决方案

 1public class StaticInnerClassSingleton {
 2    /**
 3     * 静态内部类:随类加载而加载
 4     */
 5    private static class InnerClass{
 6        private static StaticInnerClassSingleton staticInnerClassSingleton = new StaticInnerClassSingleton();
 7    }
 8
 9    /**
10     * 全局访问点
11     * @return
12     */
13    public static StaticInnerClassSingleton getInstance(){
14        return InnerClass.staticInnerClassSingleton;
15    }
16
17    /**
18     * 私有化无参构造函数,如果实例已经存在则抛出异常
19     */
20    private StaticInnerClassSingleton(){
21        if(InnerClass.staticInnerClassSingleton != null){
22            throw new RuntimeException("单例构造器禁止反射调用");
23        }
24    }
25}

饿汉式

 1public class HungrySingleton implements Serializable,Cloneable{
 2  
 3    private final static HungrySingleton hungrySingleton;
 4  
 5    //随类加载而初始化
 6    static{
 7        hungrySingleton = new HungrySingleton();
 8    }
 9
10    private HungrySingleton(){
11        if(hungrySingleton != null){
12            throw new RuntimeException("单例构造器禁止反射调用");
13        }
14    }
15
16    /**
17     * 全局访问点
18     * @return
19     */
20    public static HungrySingleton getInstance(){
21        return hungrySingleton;
22    }
23}

序列化破坏单例模式的解决方案
HungrySingleton

 1public class HungrySingleton implements Serializable,Cloneable{
 2
 3    private final static HungrySingleton hungrySingleton;
 4
 5    //随类加载而初始化
 6    static{
 7        hungrySingleton = new HungrySingleton();
 8    }
 9
10    private HungrySingleton(){
11        if(hungrySingleton != null){
12            throw new RuntimeException("单例构造器禁止反射调用");
13        }
14    }
15
16    /**
17     * 全局访问点
18     * @return
19     */
20    public static HungrySingleton getInstance(){
21        return hungrySingleton;
22    }
23
24    /**
25     * ObjectInputStream 需要用到
26     * @return
27     */
28    private Object readResolve(){
29        return hungrySingleton;
30    }
31
32    /**
33     *
34     * @return
35     * @throws CloneNotSupportedException
36     */
37    @Override
38    protected Object clone() throws CloneNotSupportedException {
39        return getInstance();
40    }
41}

测试

 1        //序列化
 2        HungrySingleton instance = HungrySingleton.getInstance();
 3        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("singleton_file"));
 4        oos.writeObject(instance);
 5
 6        //反序列化
 7        File file = new File("singleton_file");
 8        //需要用到 HungrySingleton 类的 readResolve() 方法 
 9        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
10        HungrySingleton newInstance = (HungrySingleton) ois.readObject();
11  
12        System.out.println(instance);//序列化:HungrySingleton@9807454
13        System.out.println(newInstance);//反序列化:HungrySingleton@9807454
14        System.out.println(instance == newInstance);//true

反射攻击破坏单例模式的解决方案
 懒汉式模式下无法阻止反射攻击,反射可以拿到所有成员变量做修改。
 饿汉式可以避免方式攻击:通过阻止反射调用私有构造函数
HungrySingleton

 1public class HungrySingleton implements Serializable{
 2
 3    private final static HungrySingleton hungrySingleton;
 4
 5    //随类加载而初始化
 6    static{
 7        hungrySingleton = new HungrySingleton();
 8    }
 9
10    //阻止反射调用私有构造函数:阻止反射攻击
11    private HungrySingleton(){
12        if(hungrySingleton != null){
13            throw new RuntimeException("单例构造器禁止反射调用");
14        }
15    }
16
17    /**
18     * 全局访问点
19     * @return
20     */
21    public static HungrySingleton getInstance(){
22        return hungrySingleton;
23    }
24
25    /**
26     * ObjectInputStream 需要用到
27     * @return
28     */
29    private Object readResolve(){
30        return hungrySingleton;
31    }
32}

测试

 1        Class objectClass = HungrySingleton.class;
 2        Constructor constructor = objectClass.getDeclaredConstructor();
 3        constructor.setAccessible(true);
 4
 5        HungrySingleton instance = HungrySingleton.getInstance();
 6        HungrySingleton newInstance = (HungrySingleton) constructor.newInstance();
 7
 8        System.out.println(instance);
 9        System.out.println(newInstance);
10        System.out.println(instance == newInstance);

会抛出异常,防止反射攻击破坏单例模式

1Exception in thread "main" java.lang.reflect.InvocationTargetException
2	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
3	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
4	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
5	at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
6	at com.geely.design.pattern.creational.singleton.Test.main(Test.java:65)
7Caused by: java.lang.RuntimeException: 单例构造器禁止反射调用
8	at com.geely.design.pattern.creational.singleton.HungrySingleton.<init>(HungrySingleton.java:17)
9	... 5 more

枚举类(最佳实践:可以防止序列化和反射攻击)

 1public enum EnumInstance {
 2    INSTANCE{
 3        protected  void printTest(){
 4            System.out.println("Geely Print Test");
 5        }
 6    };
 7    protected abstract void printTest();
 8  
 9    private Object data;
10    public Object getData() {
11        return data;
12    }
13    public void setData(Object data) {
14        this.data = data;
15    }
16  
17    public static EnumInstance getInstance(){
18        return INSTANCE;
19    }
20}

容器单例
ContainerSingleton

 1public class ContainerSingleton {
 2
 3    private ContainerSingleton(){
 4
 5    }
 6    private static Map<String,Object> singletonMap = new ConcurrentHashMap<String, Object>();
 7
 8    public static void putInstance(String key,Object instance){
 9        if(StringUtils.isNotBlank(key) && instance != null){
10            if(!singletonMap.containsKey(key)){
11                singletonMap.put(key,instance);
12            }
13        }
14    }
15
16    public static Object getInstance(String key){
17        return singletonMap.get(key);
18    }
19}

线程单例(不保证全局唯一,但是可以保证线程唯一)

1同步锁:时间换空间
2ThreadLocal:空间换时间(线程间隔离,每个线程都有一个实例,并不是真正意义上的单例)

ThreadLocalInstance

 1public class ThreadLocalInstance {
 2    private static final ThreadLocal<ThreadLocalInstance> threadLocalInstanceThreadLocal
 3             = new ThreadLocal<ThreadLocalInstance>(){
 4        @Override
 5        protected ThreadLocalInstance initialValue() {
 6            return new ThreadLocalInstance();
 7        }
 8    };
 9    private ThreadLocalInstance(){
10
11    }
12
13    public static ThreadLocalInstance getInstance(){
14        return threadLocalInstanceThreadLocal.get();
15    }
16
17}

案例:RunTime、Desktop

原形模式

 原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
 不需要知道任何创建的细节,不调用构造函数。
 创建型

 1# 适用场景
 2* 类初始化消耗较多资源
 3* new产生的一个对象需要非常繁琐的过程(数据准备、访问权限等)
 4* 构造函数比较复杂
 5* 循环体中生产大量对象时
 6
 7# 优点
 8* 原型模式性能比直接new一个对象性能高(在内存中进行二进制流拷贝)
 9* 简化创建过程
10
11# 缺点
12* 必须配备克隆方法
13* 对克隆复杂对象或对克隆出的对象进行复杂改造时,容易引入风险
14* 深拷贝、浅拷贝要运用得当
15
16# 深克隆
17	引用类型指向不同的对象(用于克隆引用类型的成员变量)
18
19# 浅克隆
20	可用于克隆基本类型的成员变量

Mail

 1public class Mail implements Cloneable{
 2    private String name;
 3    private String emailAddress;
 4    private String content;
 5    public Mail(){
 6        System.out.println("Mail Class Constructor");
 7    }
 8
 9    public String getName() {
10        return name;
11    }
12
13    public void setName(String name) {
14        this.name = name;
15    }
16
17    public String getEmailAddress() {
18        return emailAddress;
19    }
20
21    public void setEmailAddress(String emailAddress) {
22        this.emailAddress = emailAddress;
23    }
24
25    public String getContent() {
26        return content;
27    }
28
29    public void setContent(String content) {
30        this.content = content;
31    }
32
33    @Override
34    public String toString() {
35        return "Mail{" +
36                "name='" + name + '\'' +
37                ", emailAddress='" + emailAddress + '\'' +
38                ", content='" + content + '\'' +
39                '}'+super.toString();
40    }
41
42    @Override
43    protected Object clone() thro	ws CloneNotSupportedException {
44        System.out.println("clone mail object");
45        return super.clone();
46    }
47}

MailUtil

1public class MailUtil {
2    public static void sendMail(Mail mail){
3        String outputContent = "向{0}同学,邮件地址:{1},邮件内容:{2}发送邮件成功";
4        System.out.println(MessageFormat.format(outputContent,mail.getName(),mail.getEmailAddress(),mail.getContent()));
5    }
6    public static void saveOriginMailRecord(Mail mail){
7        System.out.println("存储originMail记录,originMail:"+mail.getContent());
8    }
9}

Test

 1public class Test {
 2    public static void main(String[] args) throws CloneNotSupportedException {
 3        //假设 new 一个 Mail 对象非常复杂,非常消耗性能。
 4        Mail mail = new Mail();
 5        mail.setContent("初始化模板");
 6        System.out.println("初始化mail:"+mail);//初始化mail:Mail{name='null', emailAddress='null', content='初始化模板'}com.geely.design.pattern.creational.prototype.Mail@7530d0a
 7
 8        for(int i = 0;i < 10;i++){
 9            //使用原始的mail进行clone
10            Mail mailTemp = (Mail) mail.clone();
11            mailTemp.setName("姓名"+i);
12            mailTemp.setEmailAddress("姓名"+i+"@imooc.com");
13            mailTemp.setContent("恭喜您,此次慕课网活动中奖了");
14            MailUtil.sendMail(mailTemp);
15            System.out.println("克隆的mailTemp:"+mailTemp);
16        }
17
18        MailUtil.saveOriginMailRecord(mail);//存储originMail记录,originMail:初始化模板
19    }
20}

深拷贝(默认是浅克隆)
Pig

 1public class Pig implements Cloneable{
 2    private String name;
 3    private Date birthday;
 4
 5    public Pig(String name, Date birthday) {
 6        this.name = name;
 7        this.birthday = birthday;
 8    }
 9
10    public String getName() {
11        return name;
12    }
13
14    public void setName(String name) {
15        this.name = name;
16    }
17
18    public Date getBirthday() {
19        return birthday;
20    }
21
22    public void setBirthday(Date birthday) {
23        this.birthday = birthday;
24    }
25
26    @Override
27    protected Object clone() throws CloneNotSupportedException {
28        Pig pig = (Pig)super.clone();
29
30        //深克隆
31        pig.birthday = (Date) pig.birthday.clone();
32        return pig;
33    }
34
35    @Override
36    public String toString() {
37        return "Pig{" +
38                "name='" + name + '\'' +
39                ", birthday=" + birthday +
40                '}'+super.toString();
41    }
42}

Test

 1public class Test {
 2    public static void main(String[] args) throws CloneNotSupportedException, NoSuchMethodException, InvocationTargetException, IllegalAccessException {
 3        Date birthday = new Date(0L);
 4        Pig pig1 = new Pig("佩奇",birthday);
 5        Pig pig2 = (Pig) pig1.clone();
 6        System.out.println(pig1);
 7        System.out.println(pig2);
 8
 9        pig1.getBirthday().setTime(666666666666L);
10
11        System.out.println(pig1);//Pig{name='佩奇', birthday=Sat Feb 16 09:11:06 CST 1991}com.geely.design.pattern.creational.prototype.clone.Pig@4fca772d
12        System.out.println(pig2);//Pig{name='佩奇', birthday=Thu Jan 01 08:00:00 CST 1970}com.geely.design.pattern.creational.prototype.clone.Pig@9807454
13    }
14}

案例:ArrayList、HashMap、CacheKey(Mybatis)

外观模式

 又叫门面模式,提供了一个统一的接口,用来访问子系统中的一群接口。
 外观模式定义一个高层接口,让子系统更容易使用。
 结构型

 1# 适用场景
 2* 子系统越来越复杂,增加外观模式提供简单调用接口
 3* 构建多层系统结构,利用外观对象作为每层的入口,简化层间调用
 4
 5# 优点
 6* 简化了调用过程,无需了解深入子系统,防止带来风险。
 7* 减少系统依赖、松散耦合
 8* 更好的划分访问层次
 9
10# 缺点
11* 增加子系统、扩展子系统行为容易引入风险
12* 不符合开闭原则
13
14# 外观-相关设计模式
15* 外加模式和中介者模式
16* 外观模式和单例模式
17* 外观模式和抽象工厂模式

外观模式

PointsGift

 1public class PointsGift {
 2    private String name;
 3
 4    public PointsGift(String name) {
 5        this.name = name;
 6    }
 7
 8    public String getName() {
 9        return name;
10    }
11}

QualifyService

1public class QualifyService {
2    public boolean isAvailable(PointsGift pointsGift){
3        System.out.println("校验"+pointsGift.getName()+" 积分资格通过,库存通过");
4        return true;
5    }
6}

PointsPaymentService

1public class PointsPaymentService {
2    public boolean pay(PointsGift pointsGift){
3        //扣减积分
4        System.out.println("支付"+pointsGift.getName()+" 积分成功");
5        return true;
6    }
7}

ShippingService

1public class ShippingService {
2    public String shipGift(PointsGift pointsGift){
3        //物流系统的对接逻辑
4        System.out.println(pointsGift.getName()+"进入物流系统");
5        String shippingOrderNo = "666";
6        return shippingOrderNo;
7    }
8}

GiftExchangeService

 1/**
 2 * 把多个子系统封装在一起,只对外提供一个外观(门面)类提供服务,调用者无需知道各个子系统的逻辑
 3 */
 4public class GiftExchangeService {
 5    private QualifyService qualifyService = new QualifyService();
 6    private PointsPaymentService pointsPaymentService = new PointsPaymentService();
 7    private ShippingService shippingService = new ShippingService();
 8
 9    public void giftExchange(PointsGift pointsGift){
10        if(qualifyService.isAvailable(pointsGift)){
11            //资格校验通过
12            if(pointsPaymentService.pay(pointsGift)){
13                //如果支付积分成功
14                String shippingOrderNo = shippingService.shipGift(pointsGift);
15                System.out.println("物流系统下单成功,订单号是:"+shippingOrderNo);
16            }
17        }
18    }
19}

Test

1public class Test {
2    public static void main(String[] args) {
3        PointsGift pointsGift = new PointsGift("T恤");
4        GiftExchangeService giftExchangeService = new GiftExchangeService();
5        giftExchangeService.giftExchange(pointsGift);
6    }
7}

测试结果

1校验T恤 积分资格通过,库存通过
2支付T恤 积分成功
3T恤进入物流系统
4物流系统下单成功,订单号是:666

案例:JdbcUtils(Spring)、Configuration(Mybatis)、RequestFacade(Tomcat)

装饰者

 在不改变原有对象的基础之上,将功能附加到对象上。

 提供了比继承更有弹性的替代方案(扩展原有对象功能)。

 结构型

 1# 使用场景
 2* 扩展一个类的功能或给一个类添加附加职责
 3* 动态的给一个对象添加功能,这些功能可以再动态的撤销
 4
 5# 优点
 6* 继承的有力补充,比继承灵活,不改变原有对象的情况下给一个对象扩展功能(动态扩展功能,运行期间决定增加的功能)
 7* 通过使用不同装饰类以及这些装饰类的排列组合,可以实现不同效果
 8* 符合开闭原则
 9
10# 缺点
11* 会出现更多的代码,更多的类,增加程序复杂性
12* 动态装饰时,多层装饰时会更复杂
13
14# 关联其他的设计模式
15* 装饰者模式、代理模式
16* 装饰者模式、适配器模式
17

装饰者

ABattercake(被装饰者)

1public abstract class ABattercake {
2    protected abstract String getDesc();
3    protected abstract int cost();
4}
5

Battercake

 1public class Battercake extends ABattercake {
 2    @Override
 3    protected String getDesc() {
 4        return "煎饼";
 5    }
 6
 7    @Override
 8    protected int cost() {
 9        return 8;
10    }
11}
12

AbstractDecorator(抽象装饰者)

 1public abstract class AbstractDecorator extends ABattercake {
 2    private ABattercake aBattercake;
 3
 4    public AbstractDecorator(ABattercake aBattercake) {
 5        this.aBattercake = aBattercake;
 6    }
 7
 8    protected abstract void doSomething();
 9
10    @Override
11    protected String getDesc() {
12        return this.aBattercake.getDesc();
13    }
14
15    @Override
16    protected int cost() {
17        return this.aBattercake.cost();
18    }
19}
20

EggDecorator(鸡蛋实体装饰类)

 1public class EggDecorator extends AbstractDecorator {
 2    public EggDecorator(ABattercake aBattercake) {
 3        super(aBattercake);
 4    }
 5
 6    @Override
 7    protected void doSomething() {
 8
 9    }
10
11    @Override
12    protected String getDesc() {
13        return super.getDesc()+" 加一个鸡蛋";
14    }
15
16    @Override
17    protected int cost() {
18        return super.cost()+1;
19    }
20}
21

SausageDecorator(香肠实体装饰类)

 1public class SausageDecorator extends AbstractDecorator{
 2    public SausageDecorator(ABattercake aBattercake) {
 3        super(aBattercake);
 4    }
 5
 6    @Override
 7    protected void doSomething() {
 8
 9    }
10
11    @Override
12    protected String getDesc() {
13        return super.getDesc()+" 加一根香肠";
14    }
15
16    @Override
17    protected int cost() {
18        return super.cost()+2;
19    }
20}

Test

 1public class Test {
 2    public static void main(String[] args) {
 3        ABattercake aBattercake;
 4        aBattercake = new Battercake();
 5        aBattercake = new EggDecorator(aBattercake);
 6        aBattercake = new EggDecorator(aBattercake);
 7        aBattercake = new SausageDecorator(aBattercake);
 8  
 9        System.out.println(aBattercake.getDesc()+" 销售价格:"+aBattercake.cost());
10        //煎饼 加一个鸡蛋 加一个鸡蛋 加一根香肠 销售价格:12
11    }
12}

案例

1* BufferedReader:Reader是一个抽象类,BufferedReader装饰Reader. 
2* Servlet:SessionRepositoryRequestWrapper.

适配器

 将一个类的接口转换成客户期望的另一个接口

 使原本接口不兼容的类可以一起工作

 结构型

 1# 适用场景
 2* 已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
 3* 不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案。
 4
 5# 优点
 6* 能提高类的透明性和复用,现有的类复用但不需要改变
 7* 目标类和适配器类解耦,提高程序扩展性
 8* 符合开闭原则
 9
10# 缺点
11* 适配器编写过程需要全面考虑,可能会增加系统的复杂性。
12* 增加系统代码可读的难度
13
14# 适配器-扩展
15* 对象适配器
16* 类适配器

方式一:类适配器模式(继承)
适配器模式

Adaptee

1public class Adaptee {
2    public void adapteeRequest(){
3        System.out.println("被适配者的方法");
4    }
5}

Adapter

1public class Adapter extends Adaptee implements Target{
2    @Override
3    public void request() {
4        //...
5        super.adapteeRequest();
6        //...
7    }
8}

ConcreteTarget

1public class ConcreteTarget implements Target {
2    @Override
3    public void request() {
4        System.out.println("concreteTarget目标方法");
5    }
6}

Target

1public interface Target {
2    void request();
3}

Test

1public class Test {
2    public static void main(String[] args) {
3        Target target = new ConcreteTarget();
4        target.request();//concreteTarget目标方法
5
6        Target adapterTarget = new Adapter();
7        adapterTarget.request();//被适配者的方法
8    }
9}

方式二:对象适配器模式(组合优先于继承)
创建对象

Adaptee

1public class Adaptee {
2    public void adapteeRequest(){
3        System.out.println("被适配者的方法");
4    }
5}

Adapter

 1public class Adapter implements Target{
 2    private Adaptee adaptee = new Adaptee();
 3
 4    @Override
 5    public void request() {
 6        //...
 7        adaptee.adapteeRequest();
 8        //...
 9    }
10}

ConcreteTarget

1public class ConcreteTarget implements Target {
2    @Override
3    public void request() {
4        System.out.println("concreteTarget目标方法");
5    }
6}

Target

1public interface Target {
2    void request();
3}

Test

1public class Test {
2    public static void main(String[] args) {
3        Target target = new ConcreteTarget();
4        target.request();//concreteTarget目标方法
5
6        Target adapterTarget = new Adapter();
7        adapterTarget.request();//被适配者的方法
8    }
9}

220 交流电通过适配器变为直流电 5V
AC220

1public class AC220 {
2    public int outputAC220V(){
3        int output = 220;
4        System.out.println("输出交流电"+output+"V");
5        return output;
6    }
7}

DC5

1public interface DC5 {
2    int outputDC5V();
3}

PowerAdapter

 1public class PowerAdapter implements DC5{
 2    private AC220 ac220 = new AC220();
 3
 4    @Override
 5    public int outputDC5V() {
 6        int adapterInput = ac220.outputAC220V();
 7        //变压器...
 8        int adapterOutput = adapterInput/44;
 9
10        System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V"+"输出DC:"+adapterOutput+"V");
11        return adapterOutput;
12    }
13}

Test

1public class Test {
2    public static void main(String[] args) {
3        DC5 dc5 = new PowerAdapter();
4        dc5.outputDC5V();//使用PowerAdapter输入AC:220V输出DC:5V
5    }
6}

案例:XmlAdapter(XML 序列化和反序列化)、JpaVendorAdapter

享元模式

 提高了减少对象数量(减少内存占用,提高性能),从而改善应用所需的对象结构的方式。
 运用共享技术有效地支持大量细粒度的对象。
 结构型。

 1# 适用场景
 2* 常常应用于系统底层的开发,以便解决系统的性能问题。
 3* 系统有大量相似对象、需要缓冲池的场景。
 4
 5# 优点
 6* 减少对象的创建,降低内存中对象的数据量,降低系统的内存,提高效率。
 7* 减少内存之外的其他资源占用
 8
 9# 缺点
10* 关注内/外部状态、关注线程安全问题
11* 使系统、程序的逻辑复杂化
12
13# 扩展
14* 内部状态:享元对象的一个属性,该属性不会随着外部的环境变化而变化。
15* 外部状态:记录在享元对象的外部,不可以被共享的状态。
16
17# 享元模式关联的其他模式
18* 享元模式和代理模式
19* 享元模式和单例模式

享元模式

Employee

1public interface Employee {
2    void report();
3}

Manager

 1public class Manager implements Employee {
 2    @Override
 3    public void report() {
 4        System.out.println(reportContent);
 5    }
 6    private String title = "部门经理"; //内部状态
 7    private String department; //外部状态
 8    private String reportContent; 
 9
10    public void setReportContent(String reportContent) {
11        this.reportContent = reportContent;
12    }
13
14    public Manager(String department) {
15        this.department = department;
16    }
17}

EmployeeFactory

 1public class EmployeeFactory {
 2    private static final Map<String,Employee> EMPLOYEE_MAP = new HashMap<String,Employee>();
 3
 4    public static Employee getManager(String department){
 5        Manager manager = (Manager) EMPLOYEE_MAP.get(department);
 6
 7        if(manager == null){
 8            manager = new Manager(department);
 9            System.out.print("创建部门经理:"+department);
10            String reportContent = department+"部门汇报:此次报告的主要内容是......";
11            manager.setReportContent(reportContent);
12            System.out.println(" 创建报告:"+reportContent);
13            EMPLOYEE_MAP.put(department,manager);
14
15        }
16        return manager;
17    }
18}

Test

 1public class Test {
 2    //部门列表
 3    private static final String departments[] = {"RD","QA","PM","BD"};
 4
 5    public static void main(String[] args) {
 6        for(int i=0; i<10; i++){
 7            String department = departments[(int)(Math.random() * departments.length)];
 8            Manager manager = (Manager) EmployeeFactory.getManager(department);
 9            manager.report();
10        }
11    }
12
13}

控制台输出

 1创建部门经理:PM 创建报告:PM部门汇报:此次报告的主要内容是......
 2PM部门汇报:此次报告的主要内容是......
 3创建部门经理:BD 创建报告:BD部门汇报:此次报告的主要内容是......
 4BD部门汇报:此次报告的主要内容是......
 5PM部门汇报:此次报告的主要内容是......
 6BD部门汇报:此次报告的主要内容是......
 7创建部门经理:QA 创建报告:QA部门汇报:此次报告的主要内容是......
 8QA部门汇报:此次报告的主要内容是......
 9BD部门汇报:此次报告的主要内容是......
10BD部门汇报:此次报告的主要内容是......
11QA部门汇报:此次报告的主要内容是......
12创建部门经理:RD 创建报告:RD部门汇报:此次报告的主要内容是......
13RD部门汇报:此次报告的主要内容是......
14QA部门汇报:此次报告的主要内容是......

案例:String、数据库连接池、Integer.valueOf(100)
 源码解析

1    public static Integer valueOf(int i) {
2        if (i >= IntegerCache.low && i <= IntegerCache.high)
3            return IntegerCache.cache[i + (-IntegerCache.low)];
4        return new Integer(i);
5    }

 测试 Integer.valueOf()

 1public class Test {
 2
 3        Integer a = Integer.valueOf(100);
 4        Integer b = 100;
 5
 6        Integer c = Integer.valueOf(1000);
 7        Integer d = 1000;
 8
 9        System.out.println("a==b:"+(a==b));//a==b:true
10        System.out.println("c==d:"+(c==d));//c==d:false
11    }
12}

组合模式

 将对象组合成树形结构以表示 “部分-整体” 的层次结构。

 组合模式使客户端对单个对象和组合对象保持一致的方式处理。

 结构型

组合-定义与类型

 1# 适用场景
 2* 希望客户端可以忽略组合对象与单个对象的差异时
 3* 处理一个树形结构时
 4
 5# 优点
 6* 清楚地定义分层次的复杂对象,表示对象的全部或部分层次
 7* 让客户端忽略了层次的差异,方便对整个层次结构进行控制
 8* 简化客户端代码
 9* 符合开闭原则
10
11# 缺点
12* 限制类型时会比较复杂
13* 使设计变得更加抽象
14
15# 组合模式-相关设计模式
16* 组合模式和访问者模式

组合模式

CatalogComponent

 1public abstract class CatalogComponent {
 2
 3    //CourseCatalog
 4    public void add(CatalogComponent catalogComponent){
 5        throw new UnsupportedOperationException("不支持添加操作");
 6    }
 7
 8    //CourseCatalog
 9    public void remove(CatalogComponent catalogComponent){
10        throw new UnsupportedOperationException("不支持删除操作");
11    }
12
13    //Course / CourseCatalog
14    public String getName(CatalogComponent catalogComponent){
15        throw new UnsupportedOperationException("不支持获取名称操作");
16    }
17
18    //Course
19    public double getPrice(CatalogComponent catalogComponent){
20        throw new UnsupportedOperationException("不支持获取价格操作");
21    }
22  
23    //Course
24    public void print(){
25        throw new UnsupportedOperationException("不支持打印操作");
26    }
27}

Course

 1public class Course extends CatalogComponent {
 2
 3    private String name;
 4    private double price;
 5
 6    public Course(String name, double price) {
 7        this.name = name;
 8
 9        this.price = price;
10    }
11
12    @Override
13    public String getName(CatalogComponent catalogComponent) {
14        return this.name;
15    }
16
17    @Override
18    public double getPrice(CatalogComponent catalogComponent) {
19        return this.price;
20    }
21
22    @Override
23    public void print() {
24        System.out.println("Course Name:"+name+" Price:"+price);
25    }
26}

CourseCatalog

 1public class CourseCatalog extends CatalogComponent {
 2    private List<CatalogComponent> items = new ArrayList<CatalogComponent>();
 3    private String name;
 4    private Integer level;
 5
 6    public CourseCatalog(String name,Integer level) {
 7        this.name = name;
 8        this.level = level;
 9    }
10
11    @Override
12    public void add(CatalogComponent catalogComponent) {
13        items.add(catalogComponent);
14    }
15
16    @Override
17    public String getName(CatalogComponent catalogComponent) {
18        return this.name;
19    }
20
21    @Override
22    public void remove(CatalogComponent catalogComponent) {
23        items.remove(catalogComponent);
24    }
25
26    @Override
27    public void print() {
28        System.out.println(this.name);
29        for(CatalogComponent catalogComponent : items){
30            if(this.level != null){
31                for(int  i = 0; i < this.level; i++){
32                    System.out.print("  ");
33                }
34            }
35            catalogComponent.print();
36        }
37    }
38
39}

控制台输出

1
2慕课网课程主目录
3  Course Name:Linux课程 Price:11.0
4  Course Name:Windows课程 Price:11.0
5  Java课程目录
6    Course Name:Java电商一期 Price:55.0
7    Course Name:Java电商二期 Price:66.0
8    Course Name:Java设计模式 Price:77.0 

案例:awt.Container、HashMap.putAll()、ArrayList.addAll()

桥接模式

 将抽象部分与它的具体实现部分分离,使它们都可以独立地变化(一定程度上实现解耦)。

 通过组合的方式建立两个类之间联系,而不是继承。

 结构型

 1# 适用场景
 2* 抽象和具体实现之间增加更多的灵活性。
 3* 一个类存在两个(或多个)独立变化的维度,且这两个(或多个)维度都需要独立进行扩展。
 4* 不希望使用继承,或因为多层继承导致系统类的个数剧增。
 5
 6# 优点
 7* 分离抽象部分及其具体实现部分
 8* 提高了系统的可扩展性
 9* 符合开闭原则
10* 符合合成复用原则
11* 组合优于继承
12
13# 缺点
14* 增加系统的理解与设计难度
15* 需要正确地识别出系统中两个独立变化的维度
16
17# 桥接 - 相关设计模式
18* 桥接模式和组合模式
19* 桥接模式和适配器模式

桥接

Account

1public interface Account {
2    Account openAccount();
3    void showAccountType();
4}

DepositAccount

 1public class DepositAccount implements Account {
 2    @Override
 3    public Account openAccount() {
 4        System.out.println("打开定期账号");
 5        return new DepositAccount();
 6    }
 7
 8    @Override
 9    public void showAccountType() {
10        System.out.println("这是一个定期账号");
11    }
12}

SavingAccount

 1public class SavingAccount implements Account {
 2    @Override
 3    public Account openAccount() {
 4        System.out.println("打开活期账号");
 5        //...
 6        return new SavingAccount();
 7    }
 8
 9    @Override
10    public void showAccountType() {
11        System.out.println("这是一个活期账号");
12    }
13}

Bank

1public abstract class Bank {
2    protected Account account;
3    public Bank(Account account){
4        this.account = account;
5    }
6    abstract Account openAccount();
7}

ABCBank

 1public class ABCBank extends Bank {
 2    public ABCBank(Account account) {
 3        super(account);
 4    }
 5
 6    @Override
 7    Account openAccount() {
 8        System.out.println("打开中国农业银行账号");
 9        account.openAccount();//委托业务实现
10        return account;
11    }
12}

ICBCBank

 1public class ICBCBank extends Bank {
 2    public ICBCBank(Account account) {
 3        super(account);
 4    }
 5
 6    @Override
 7    Account openAccount() {
 8        System.out.println("打开中国工商银行账号");
 9        account.openAccount();//委托业务实现
10        return account;
11    }
12}

Test

 1public class Test {
 2    public static void main(String[] args) {
 3        Bank icbcBank = new ICBCBank(new DepositAccount());
 4        Account icbcAccount = icbcBank.openAccount();
 5        icbcAccount.showAccountType();
 6
 7        Bank icbcBank2 = new ICBCBank(new SavingAccount());
 8        Account icbcAccount2 = icbcBank2.openAccount();
 9        icbcAccount2.showAccountType();
10
11        Bank abcBank = new ABCBank(new SavingAccount());
12        Account abcAccount = abcBank.openAccount();
13        abcAccount.showAccountType();
14    }
15}

控制台输出

 1打开中国工商银行账号
 2打开定期账号
 3这是一个定期账号
 4
 5打开中国工商银行账号
 6打开活期账号
 7这是一个活期账号
 8
 9打开中国农业银行账号
10打开活期账号
11这是一个活期账号

案例:Driver(JDBC,MySQL、Oracle 都实现了 Driver 接口)、

代理模式

 为其他对象提供一种代理,以控制对这个对象的访问。
 代理对象在客户端和目标对象之间起到中介的作用。
 结构型

 1# 适用场景
 2* 保护目标对象(客户端无需于目标对象直接接触,而是和代理对象直接接触)
 3* 增强目标对象
 4
 5# 优点
 6* 代理模式能将代理对象与真实被调用的目标对象分离
 7* 一定程度上降低了系统的耦合度,扩展性好
 8* 保护目标对象
 9* 增强目标对象
10
11# 缺点
12* 会造成系统设计中类的数目增加
13* 在客户端和目标对象之间引入代理对象,会造成请求处理速度变慢
14* 增加系统的复杂度
15
16# 扩展
17* 静态代理
18* 动态代理(JDK动态代理只支持实现接口的类、CGLib可以代理类,但不支持final修饰的类或方法)
19
20# Spring 代理选择
21* 当 Bean 有实现接口时,Spring 就会用 JDK 的动态代理
22* 当 Bean 没有实现接口时,Spring 使用 CGlib
23* 可以强制使用 CGlib
24	在 spring 配置中加入 <aop:aspectj-autoproxy proxy-target-class="true"/>
25
26# 代理速度对比
27* CGLib:底层通过ASM字节码生成,性能高于JAVA反射。
28* JDK动态代理:JAVA反射。
29* JDK8 的 JDK动态代理 性能大约比 CGLib 快20%左右。
30
31# 代理 - 相关设计模式
32* 代理模式和装饰模式
33* 代理模式和适配器模式

作者:Soulboy