六大设计原则

来源:互联网 发布:模特接单软件 编辑:程序博客网 时间:2024/06/01 23:48

*说明:本文参考书籍《设计模式之禅》第2版,作者:秦小波,章节:第1章~第6章。

六大设计原则,按照英文首字母概括为SOLLID,可简单理解为-solid-稳定的。

这六大设计原则如下:

Single Responsibility Principle:单一职责原则

Open Closed Principle:开闭原则

Liskov Substitution Principle:里氏替换原则

Law of Demeter:迪米特法则

Interface Segregation Principle:接口隔离原则

Dependence Inversion Principle:依赖倒置原则

1.单一职责原则(SRP)

1.1定义

应该有且仅有一个原因引起类的变更。

1.2示例

image

IPhone这个接口,并不是单一职责,而是两个职责:一个是协议管理-dial()和hangup();另一个是数据传送-chat()。

协议接通的变化、数据传送的变化都会引起这个接口或实现类的变化。

这两个职责互不影响,可拆分成两个接口。

image

 

2.开闭原则(OCP)

2.1定义

一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。

直白的讲:一个软件实体应该通过扩展来实现变化,而不是通过修改已有的代码来实现变化。

2.2示例

image

书店开始打折销售,如何应对这一变化呢?

修改接口——导致实现类NovelBook和BookStore的main方法都要修改。该方案否定。

修改实现类——由于采购人员也要看价格,会因信息不对称导致决策失误。该方案不是最优。

*通过扩展实现变化——增加一个子类OffNovelBook,并覆写getPrice方法,不需修改原有代码。最优方案。

image

 

 

3.里氏替换原则(LSP)

3.1定义

所有引用基类的地方必须能透明地使用其子类的对象。

直白的讲:只要父类能出现的地方子类就可以出现,但是反过来就不行,有子类的地方,父类未必就能适应。向下转型是不安全的

3.2示例

image

士兵使用AUG狙击枪杀敌。

正确代码:

class Client {public static void main(String[] args) {//产生三毛这个狙击手Snipper sanMao = new Snipper();sanMao.setRifle(new AUG());sanMao.killEnemy();}}

这里直接把子类传递进来。


错误代码:

class Client {public static void main(String[] args) {//产生三毛这个狙击手Snipper sanMao = new Snipper();sanMao.setRifle(AUG(new Rifle()));sanMao.killEnemy();}}

这里我们不能直接使用父类传递进来。

 

4.迪米特法则(LoD)

4.1定义

也称为最少知识原则。即:一个对象应该对其他对象有最少的了解。

4.2示例

朋友类:出现在成员变量、成员方法的输入输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。

image 

示例中的Girl类是出现在Teacher类的command方法体内,因此不属于Teacher类的朋友类。

迪米特法则告诉我们一个类只和朋友类交流,Teacher类却与陌生类Girl有了交流,破坏了Teacher类的健壮性。

方法是类的一个行为,类竟然不知到自己的行为与其他类产生了依赖关系,这是不允许的,严重违反了迪米特法则。

修改后的类图如下:

image

 

5.接口隔离原则(ISP)

5.1定义

接口尽量细化,同时接口中的方法尽量少。

5.2示例

image

产生了问题:气质型Girl不需要具备goodLooking以及niceFigure的。所以接口封装过度!

修改后的类图如下:

image

 

6.依赖倒置原则(DIP)

6.1定义

*模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;

*接口或抽象类不依赖于实现类;

*实现类依赖接口或抽象类。

6.2示例

image

产生了问题:Driver不仅开Benz还开BMW,可是Driver类和Benz类之间是紧耦合的关系,导致系统可维护性降低,可读性降低。

修改后的类图如下:

image

在使用的过程中遵循以下几个规则:

*每个类尽量都有接口或抽象类,或者二者兼备

*变量的表面类型尽量是接口或者是抽象类

*任何类都不应该从具体类派生

*尽量不要覆写基类的方法

*接口负责定义public属性和方法,并且声明与其他对象的依赖关系;抽象类负责公共构造部分的实现;实现类准确的实现业务逻辑,同时在适当的时候对父类进行细化。

原创粉丝点击