设计模式1-原则

来源:互联网 发布:x77论坛大陆永久域名 编辑:程序博客网 时间:2024/06/05 17:35

设计原则


单一职责原则(SRP,Simple Responsibility Principle)


优点:

l   类的复杂性降低,实现什么职责都有清晰明确的定义;

l   可读性提高

l   可维护性提高

l   变更引起的风险降低,如果接口的单一职责做得好,一个接口修改只对相应的实现类有影响,对其他的接口无影响,这对系统的扩展性、维护性都有非常大的帮助。

 

对于单一职责原则,接口一定要做到单一职责,类的设计尽量做到只有一个原因引起变化。

 

 

 

里氏替换原则(LSP,Liskov Substitution Principle)

如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。

       所有引用基类的地方必须能透明地使用其子类的对象。即只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。

 

       良好继承的规范:

l   子类必须完全实现父类的方法。否则就会造成子类的应用场景和父类的不一致,导致出现不符合原有设定的情况。因此子类不能完整地实现父类的方法,或者父类的某些方法在子类中已经发生改变,则建议断开父子继承关系,采用依赖、聚集、组合等关系代替继承。

l   子类可以有自己的个性。因此子类出现的地方,父类未必就可以胜任。

l   覆盖或实现父类的方法时输入参数可以被放大。接口方法传入的父类的类型,因此场景要适用父类的通用方法。输入参数放大就不会执行子类的方法,只会执行父类的方法(重载),符合接口方法的要求。如果子类的输入参数缩小,就不会执行父类的方法,只会执行子类的方法,这样就不符合接口方法的初衷。

l   覆写或实现父类的方法时输出结果可以被缩小。父类和子类的同名方法的输入参数是相同的,子类的返回值S与父类的返回值T相同或是T的子类,这就是子类覆写父类的方法。这个是正常的。

 

在项目中,采用里氏替换原则时,尽量避免子类的个性,一旦子类有个性,这个子类和父类之间的关系就很难调和了。把子类当做父类使用,子类的个性被抹杀,把子类单独作为一个业务来使用,会让代码间的耦合关系变得比较乱。

 

依赖倒置原则(DIP,Dependence Inversion Principle)

依赖正置就是类间的依赖是实实在在的实现类间的依赖,也就是面向实现编程,这也是正常人的思维方式,我要开奔驰车就依赖奔驰车,我要使用笔记本电脑就直接依赖笔记本电脑,而编写程序需要的是对现实世界的事物进行抽象,抽象的结果就是有了抽象类和接口,然后我们根据系统设计的需要产生了抽象间的依赖,代替了人们传统思维中的事物间的依赖,“倒置”就是从这里产生的。

 

依赖倒置原则:

l   高层模块不应该依赖低层模块,两者都应该依赖其抽象;

l   抽象不应该依赖细节;

l   细节应该依赖抽象。

 

Java语言:

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

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

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

 

对象依赖关系传递:

l   构造函数传递依赖对象

l   Setter方法传递依赖对象

l   接口声明依赖对象

 

 

依赖倒置原则的本质就是通过抽象(接口或抽象类)使各个类或模块的实现彼此独立,不相互影响,实现模块间的松耦合。

 

遵循规则:

l   每个类尽量都有接口或抽象类,或者抽象类和接口两者具备。这是依赖倒置的基本要求,接口和抽象类都是属于抽象的,有了抽象才可能依赖倒置。

l   变量的表面类型尽量是接口或者是抽象类。特殊的类除外,比如工具类

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

l   尽量不要覆写基类的方法。如果基类是一个抽象类,而且这个方法已经实现了,子类尽量不要覆写。

l   结合里氏替换原则使用。


接口隔离原则(ISP,Interface Segregation Principle)

客户端不应该依赖它不需要的接口。

       类间的依赖关系应该建立在最小的接口上。

       接口隔离原则与单一职责的审视角度是不相同的,单一职责要求的是类和接口职责单一,注重的是职责,这是业务逻辑上的划分,而接口隔离原则要求接口的方法尽量少。

       接口规范(接口隔离原则):

l   接口要尽量少。不能违反单一职责原则。

l   接口要高内聚。提高接口、类、模块的处理能力,减少对外的交互。

l   定制服务。单独为模块或子系统提供定制服务。比如后台系统、线上系统等。

l   接口设计是有限度的。接口的设计粒度越小,系统越灵活,这是不争的事实。但是,灵活的同时也带来了结构的复杂性,开发难度增加,可维护性,所以接口设计一定要注意适度(根据经验)。

 

接口隔离原则是对接口的定义,同时也是对类的定义,接口和类尽量使用原子接口或原子类来组装。可以通过以下几个规则来衡量:

l   一个接口只服务于一个子模块或业务逻辑。

l   通过业务逻辑压缩接口中的public方法,接口时常去回顾,尽量让接口达到“满身筋骨肉”,而不是“肥嘟嘟”的一大堆方法。

l   已经被污染了的接口,尽量去修改,若变更的风险较大,则采用适配器模式进行转化处理。

l   了解环境,拒绝盲从。环境不同,接口拆分的标准就不同。

 


迪米特法则(LoD,Law of Demeter)

       也称最少知识原则(LKP,Least KnowledgePrinciple),一个对象应该对其他对象有最少的了解。要求类间解耦。

l   只和朋友交流。一个类只和朋友交流,不与陌生类交流。类与类之间的关系是建立在类间的,而不是方法间,因此一个方法尽量不引入一个类中不存在的对象。

l   朋友间也是有距离的。尽量减少对关联类的依赖。

l   是自己的就是自己的。如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

 


开闭原则(OCP,Open-Close Principle)

 

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

       尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来完成变化。

开闭原则对扩展开放,对修改关闭,并不意味着不做任何修改,低层模块的变更,必然要有高层模块进行耦合,否则就是一个孤立无意义的代码片段。

       如何应用:

l   抽象约束。通过接口或抽象类可以约束一组可能变化的行为,并且能够实现对扩展开放。

l   元数据控制模块行为。通过配置参数等来控制模块。比如通过扩展一个子类,修改配置文件,完成业务变化。比如Spring的配置文件。

l   制定项目章程。通过遵守约定,来实现如何扩展等。

l   封装变化。将相同的变化封装到一个接口或抽象类中;将不同的变化封装到不同的接口或抽象类中,不应该有两个不同的变化出现在同一个接口或抽象类中。

 

 

0 0
原创粉丝点击