avatar

目录
java设计模式-23种设计模式

23种设计模式概述

Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
创建型模式
工厂方法模式
抽象工厂模式
建造者模式
单例模式
原型模式
结构型模式
适配器模式
装饰者模式
代理模式
外观模式
桥接模式
组合模式
享元模式
行为型模式
模板方法模式(Template Method)
策略模式(Strategy)
命令模式(Command)
中介者模式(Mediator)
观察者模式(Observer)
迭代器模式(Iteratior)
访问者模式(Visiter)
责任链模式(Chain of Responsibility)
备忘录模式(Memento)
状态模式(State)
解释器模式(Interpreter)

简单工厂模式

参考:第4章 简单工厂模式

概念

定义与类型

  • 定义:由一个工厂对象决定创建出哪一种产品类的实例
  • 创建型:不属于23种设计模式

适用场景

  • 工厂类负责创建的对象比较少
  • 客户端(应用层)只知道传入工厂类的参数,对于如何创建对象(创建对象的具体逻辑)不关心

优点

  • 只需要传入一个正确的参数,就可以获取你所需要的对象而无须知道其创建细节

缺点

  • 工厂类的职责相对过重,增加新的产品时,需要修改工厂类的判断逻辑,违背了开闭原则
  • 无法形成继承的等级结构

coding

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public abstract class Video {
public abstract void product();
}

public class JavaVideo extends Video {
@Override
public void product() {
System.out.println("录制Java课程视频");
}
}

public class Python extends Video {
@Override
public void product() {
System.out.println("录制Python的课程视频");
}
}

public class VideoFactory {
public Video getVideo(String type) {
if ("java".equalsIgnoreCase(type)) {
return new JavaVideo();
} else if ("python".equalsIgnoreCase(type)) {
return new Python();
}
return null;
}
}

public class Test {
public static void main(String[]args){
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo("java");
if (video == null) {
return;
}
video.product();
}
}

具体的产生类的方法都在工厂类里面,这个就是简单工厂模式;
但是,如果我们还要录制一个FE的前端课程,那么,我们就要对工厂类里面的方法进行扩展,那么这个并不符合开闭原则:

----------------------
改:用反射来演进一下:

public class VideoFactory {
public Video getVideo(Class clazz) {
Video video = null;
try {
video = (Video) Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return video;
}
}
public class Test {
public static void main(String[]args){
VideoFactory videoFactory = new VideoFactory();
Video video = videoFactory.getVideo(JavaVideo.class);
if (video == null) {
return;
}
video.product();
}
}

这里从一定原则上讲是符合开闭原则的:
如果我们要new什么类,那我们就只需要传入这个类的类型就可以了,而这个工厂是不需要变化的;

JDK源码解析

Code
1
2
3
Calendar
DriverManager里面的getConnection()方法
LoggerFactory这个类里面的getLogger方法

1-工厂方法模式

参考:第5章 工厂方法模式

概念

工厂方法-定义与类型

  • 定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类,工厂方法让这个类的实例化推迟到子类中进行
  • 类型:创建型
  • 两个关键词:工厂、方法
    • 工厂:用来创建对象
    • 方法:通过子类实现方法来创建对象

工厂方法-适用场景

  • 创建对象需要大量重复的代码
  • 客户端(应用层)不依赖于产品类实例如何被创建、实现等细节一个类通过子类来指定创建哪个对象

工厂方法-优点

  • 用户只需关心所需产品对应的工厂(客户端不需要知道具体产品类的类名),无须关心创建细节。加入新产品符合开闭原则,提高可扩展性

工厂方法-缺点

  • 类的个数容易过多,增加复杂度增加了系统的抽象性和理解难度
    • 类的个数增加的原因:在添加新产品的时候要添加新的产品类,而且还要提供与此产品类对应的工厂类

coding

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
public abstract class Video
public class JavaVideo extends Video
public class PythonVideo extends Video

// 把之前的工厂类改成一个抽象类,里面只留一个待实现的抽象方法
public abstract class VideoFactory {
public abstract Video getVideo();
}

【相同类型的一个产品,我们称之为产品等级,他们的等级都是在视频的这个等级上;
产品等级和产品族是区分工厂方法和抽象方法的重要概念;】

public class JavaVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}
}

public class PythonVideoFactory extends VideoFactory {
@Override
public Video getVideo() {
return new PythonVideo();
}
}

public class Test {
public static void main(String[]args){
// 需要JavaVideo直接去找对应的工厂,而不用知道JavaVideo的任何信息
// 在这段代码中 JavaVideo这个类根本没有出现
VideoFactory videoFactory = new JavaVideoFactory();
Video video = videoFactory.getVideo();
video.product();
}
}

【产品族的概念:
Java的视频,Java的手记,他们都属于Java,他们属于同一产品族。
而Java的视频,Python的视频,FE的视频来说,他们属于同一产品等级。
这个概念有点拗口,抽象工厂就是解决产品族的问题。】

jdk源码解析

Code
1
2
Iterator
URLStreamHandlerFactory

2-抽象工厂模式

参考:第6章 抽象工厂模式

概念

定义与类型

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

适用场景

  • 强调一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码

优点

  • 将一系列的产品族统一到一起创建

缺点

  • 规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改接口

产品等级结构和产品族

产品族:美的空调、美的冰箱、美的电视

产品等级结构:美的空调、海尔空调、格力空调

工厂方法针对产品等级结构、抽象工厂针对产品族

coding

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
新的要求:每一个课程不仅仅要有视频,还要有对应的手记,如果用工厂方法的方式来进行扩展的话 。这个时候,就很容易出现类爆炸的现象。

// 课程
public abstract class Video {
public abstract void produce();
}
// 手记
public abstract class Article {
public abstract void produce();
}
// 课程工厂类
public interface CourseFactory {
/** 获取视频 */
Video getVideo();

/** 获取手记 */
Article getArticle();
}

public class JavaVideo extends Video
public class JavaArticle extends Article

// java产品族的课程工厂
public class JavaCourseFactory implements CourseFactory {
@Override
public Video getVideo() {
return new JavaVideo();
}

@Override
public Article getArticle() {
return new JavaArticle();
}
}

public class PythonArticle extends Article
public class PythonVideo extends Video
public class PythonCourseFactory implements CourseFactory

// 只要是从Java产品族里面拿的肯定是Java的视频和Java的手记
public class Test {
public static void main(String[]args){
CourseFactory courseFactory = new JavaCourseFactory();
Article article = courseFactory.getArticle();
Video video = courseFactory.getVideo();
/** 只要是从Java产品族里面拿的肯定是Java的视频和Java的手记 */
article.produce();
video.produce();
}
}

【在使用抽象工厂的时候,尽量找那种固定程度比较高的,像课程里面的视频和手记,视频和手记都是必须要有的,就可以用抽象工厂模式来解决】

缺点:在新增产品等级的时候,会比较的麻烦。如果在现有的产品族里面添加新的产品等级,就违背了开闭原则了;

jdk源码解析

Code
1
2
Connection
mysql oracle属于同一个产品族

3-建造者模式

参考:第7章 建造者模式

概念

定义与类型

  • 定义:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示(炒菜 > 炒出不同的菜)
  • 用户只需要指定创建的类型就可以得到它,建造过程及细节不需要知道

使用场景

  • 一个对象具有非常复杂的内部结构(很多属性)
  • 想把复杂对象的创建和使用分离

优点

  • 创建和使用分离

缺点:

  • 产生多余的builder对象
  • 产品内部发生变化,修改成本较大

区别

  • 建造者模式更注重方法的调用顺序,可以创建复杂产品(不仅要创造产品,还要知道组成部件)
  • 工厂模式更注重创建产品

coding

java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
// 课程类
public class Course {
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
/** 问题和答案 */
private String courseQA;
}

public abstract class CourseBuilder {

public abstract void buildCourseName(String courseName);
public abstract void buildCoursePPT(String coursePPT);
public abstract void buildCourseVideo(String courseVideo);
public abstract void buildCourseArticle(String courseArticle);
public abstract void buildCourseQA(String courseQA);

public abstract Course makeCourse();
}

// 实现CourseBuilder 的子类
public class CourseActualBuilder extends CourseBuilder {

/** 这里把课程组合到实际的Builde当中 */
private Course course = new Course();

@Override
public void buildCourseName(String courseName) {
course.setCourseName(courseName);
}

@Override
public void buildCoursePPT(String coursePPT) {
course.setCoursePPT(coursePPT);
}
...

@Override
public Course makeCourse() {
return course;
}
}

// 教练类
public class Coach {
private CourseBuilder courseBuilder;
/** 这里的CourseBuilder通过set的方式给注入进来 */
public void setCourseBuilder(CourseBuilder courseBuilder) {
this.courseBuilder = courseBuilder;
}

public Course makeCourse(String courseName,String coursePPT,
String courseVideo,String courseArticle,String courseQA) {
this.courseBuilder.buildCourseName(courseName);
this.courseBuilder.buildCoursePPT(coursePPT);
this.courseBuilder.buildCourseVideo(courseVideo);
this.courseBuilder.buildCourseArticle(courseArticle);
this.courseBuilder.buildCourseQA(courseQA);

return this.courseBuilder.makeCourse();
}
}

public class Test {
public static void main(String[]args){
/**抽象类的引用指向子类的实现 */
CourseBuilder courseBuilder = new CourseActualBuilder();
Coach coach = new Coach();
/** 这里利用set方法注入进去 */
coach.setCourseBuilder(courseBuilder);
Course course = coach.makeCourse("Java设计模式", "Java设计模式PPT", "Java设计模式视频", "Java设计模式手记", "Java设计模式问答");
System.out.println(course);
}
}


-------------------------------------------------
演进:使用静态内部类
【把具体的实体类和实体类对应的Builder写在一个类里面,这里一个很关键的地方就是this和静态内部类的使用】
关于静态内部类:
- 外部类可以访问内部类的所有方法与属性,包括私有方法与属性
- 不能够从静态内部类的对象中访问外部类的非静态成员
- 静态内部类属于外部类,而不是属于外部类的对象

public class Course {

private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
private String courseQA;

// 可以直接访问内部类的私有属性 courseBuilder.courseName
public Course(CourseBuilder courseBuilder) {
this.courseName = courseBuilder.courseName;
this.coursePPT = courseBuilder.coursePPT;
this.courseVideo = courseBuilder.courseVideo;
this.courseArticle = courseBuilder.courseArticle;
this.courseQA = courseBuilder.courseQA;
}

// 静态内部类
public static class CourseBuilder{
private String courseName;
private String coursePPT;
private String courseVideo;
private String courseArticle;
private String courseQA;


// 返回该类本身,可以使用链式调用
public CourseBuilder builderCourseName(String courseName) {
this.courseName = courseName;
return this;
}
public CourseBuilder builderCoursePPT(String coursePPT) {
this.coursePPT = coursePPT;
return this;
}

...

// 内部类提供了某种进入外部类的窗户
public Course build() {
return new Course(this);
}
}
}

// 应用层
public class Test {
public static void main(String[]args){
// 可以按需求链式调用,许多属性可以使用默认值
Course course = new Course.CourseBuilder()
.builderCourseName("Java设计模式")
.builderCoursePPT("Java设计模式PPT")
.builderCourseVideo("Java设计模式视频")
.builderCourseArticle("Java设计模式手记")
.builderCourseQA("Java设计模式问答").build();
System.out.println(course);
}
}

源码解析

Code
1
2
StringBuilder
Guava

4-单例模式

参考:

概念

coding

jdk源码解析

5-原型模式

参考:

概念

coding

jdk源码解析

文章作者: Machine
文章链接: https://machine4869.gitee.io/2019/09/06/20190906210551001/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 哑舍
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论