设计模式的设计原则

释放双眼,带上耳机,听听看~!

对于设计模式的设计原则,网上有多个版本,分别是:七大原则、六大原则、五大原则一大法则等等。虽数量不同,基本内容基本相似。在这里我们按照七大原则的版本来讲。
设计模式六大设计原则分别是:开闭原则(Open Closed Principle,OCP)、单一职责原则 (Single Responsiblity Principle SRP)、里氏替换原则(Liskov Substitution Principle,LSP)、依赖反转原则(Dependency Inversion Principle,DIP)、接口隔离原则(Interface Segregation Principle,ISP)、合成/聚合复用原则(Composite/Aggregate Reuse Principle,CARP)、最小知识原则(Principle of Least Knowledge,PLK,也叫迪米特法则)。

  1. 开闭原则

Bertrand Meyer在他的著作《Object Oriented Software Construction》中定义开闭原则为:Software entities should be open for extension, but closed for midification,翻译:软件实体应当对扩展开放,对修改关闭。
如何理解呢?下面以代码的形式将对此进行说明(仅仅是一个举例,包括但不仅限于此)。定义一个类Cartoon,含有一个name属性、两个方法content和show;两个子类OnePiece和TomAndJerry,两个子类新增自己的属性,并对Cartoon的show方法进行重写。这种代码设计方式符合开闭原则。


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
1public class Cartoon {
2
3    protected String name;
4
5    public Cartoon(String name) {
6        this.name = name;
7    }
8
9    public String content() {
10        return "Cartoon name is " + this.name;
11    }
12
13    public void show() {
14        System.out.println(this.name);
15    }
16}
17public class OnePiece extends Cartoon {
18
19    private String time;
20    private String music;
21
22    public OnePiece(String name, String time, String music) {
23        super(name);
24        this.time = time;
25        this.music = music;
26    }
27
28    @Override
29    public void show(){
30        System.out.println(this.name);
31        System.out.println(this.time);
32        System.out.println(this.music);
33    }
34}
35public class TomAndJerry extends Cartoon {
36
37    private String time;
38
39    public TomAndJerry(String name, String time) {
40        super(name);
41        this.time = time;
42    }
43
44    @Override
45    public void show(){
46        System.out.println(this.name);
47        System.out.println(this.time);
48    }
49
50    public static void main(String[] arg){
51        TomAndJerry t = new TomAndJerry("tomAndJerry", "2000");
52        t.show();
53    }
54}
55
56
  1. 单一职责原则

Robert C. Martin提出,There should never be more than one reason for a class change,翻译:决不允许有多种原因导致一个类发生变化。
代码中StaffDuty类设计明显不合理,在公司中很少会让一个人既负责技术又负责管理。所以代码改进成技术和管理两个类。


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
1class StaffDuty{
2    void technology() {}
3    void manage(){}
4}
5
6class TechnologyStaff{
7    void ui(){}
8    void webService(){}
9    void bigData(){}
10}
11
12class ManageStaff{
13    void hr(){}
14    void finance(){}
15    void projectManage(){}
16}
17
18
  1. 里氏替换原则

Liskov在他的文章《Data Abstraction and Hierarchy》中提出: Inheritance should ensure that any property proved about supertype objects also holds for subtype objects,翻译:继承应该确保超类的性质同样适用于子类。
代码中,Calorifier2类因没有预加热功能导致heatTime方法报错,不满足里氏替换原则;Calorifier1类在满足Calorifier类功能的基础上扩展新的功能,满足里氏替换原则。


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
1class Calorifier{
2    // 预加热速度
3    Integer preHeatSpeed;
4
5    public void setHeatSpeed(Integer preHeatSpeed){
6        this.preHeatSpeed = preHeatSpeed;
7    }
8
9    public Integer heatTime(Integer targetTemperature){
10        return targetTemperature / preHeatSpeed;
11    }
12}
13class Calorifier1 extends Calorifier{
14
15    Integer deviceStatus;
16
17    public void offDevice(){
18        deviceStatus = 0;
19    }
20    public void onDevice(){
21        deviceStatus = 1;
22    }
23}
24class Calorifier2 extends Calorifier{
25    @Override
26    public void setHeatSpeed(Integer preHeatSpeed) {
27        this.preHeatSpeed = 0;
28    }
29}
30
31
  1. 依赖反转原则

Robert C.Martin提出,High level modules should not depend upon low level modules. Both should depen upon abstractions. Abstractions should not depend upon details. Details should depend upon abstractions. 翻译:高层模块不应该依赖低层模块,两者应该依赖抽象模块;抽象不应该依赖细节,细节应该依赖抽象。
我们以Person类为例,代码如下,定义一个eat方法,参数为ChinestFood;可能有人会吃WesternFood,就需要将eat方法的参数修改为WesternFood;不如直接将Person的eat方法的参数修改为Food,然后定义一个Food类,并使ChineseFood和WesternFood继承Food类


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
1class Person {
2    void eat(ChineseFood chineseFood){}
3}
4
5class Person {
6    void eat(WesternFood westernFood){}
7}
8
9class Person {
10    void eat(Food food){}
11}
12
13class Food { }
14
15class ChineseFood extends Food { }
16
17class WesternFood extends Food { }
18
19
  1. 接口隔离原则

Robert C.Martin提出,Clients should not be forced to depend on methods they do not use,翻译:客户端不应该被迫依赖它们用不到的方法。
举个栗子,如下图,不应该将所有的方法均放在一个接口中,要根据各自的功能和依赖放在一起。既方便代码阅读,也方便代码更新和问题排查。
6. 合成/聚合复用原则

尽量使用合成/聚合的方式,而不是使用继承。
举个煎蛋的栗子,采用下图的方式建类,则非常麻烦,脱离设计的初衷。如果将肤色建立一个类,并并肤色类嵌入人的类中,使人有一个属性子类肤色,就会变得非常煎蛋。
7. 最小知识原则

Ian Holland提出,Talk only your immediate friends and not to strangers,翻译:只跟你的直接朋友交流,不要跟陌生人说话。说白了就是,没有直接关系的实体类,不应该建立联系,或发生直接的调用。
以人驾驶汽车为例,方向盘(SteerWheel)、油门加速器(Accelerator)、离合器(Clutch)、手刹(HandBrake)各司其职相互没有关联,均通过人来控制。

总结:

设计模式的设计原则

给TA打赏
共{{data.count}}人
人已打赏
安全运维

MongoDB数据建模小案例:物联网时序数据库建模

2021-12-11 11:36:11

安全运维

Ubuntu上NFS的安装配置

2021-12-19 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索