Featured image of post Design Pattern Principle

Design Pattern Principle

这些天来学习设计模式的一点小结。

在写软件工程课设的过程中,我发现随着代码量增多,稍微一修改代码就有“牵一发而动全身”之感(每次看代码都想抽自己),扩展和维护及其困难,恍惚有一种过程式编程的体验。而且在许多功能和类的职责的划分上十分草率,耦合度相当的高,于是,是时候该看一看设计模式了。

单一职责原则

Single Responsibility Principle: a class should have only one reason to change.

一个类,应当只有一个引起它变化的原因;即一个类应该只有一个职责。一个类只负责一项职责。

intent

单一职责原则的核心是控制类的粒度大小、将对象解耦、提高内聚性。该原则强调对象不应该承担过多的职责,如果一个对象承担了太多的职责,那么一个职责的变化可能会削弱或抑制这个类实现其他职责的能力;当客户需要对象的某一职责时,不得不将其他不需要的职责包含进来,造成代码冗余。

conclusion

The Single Responsibility Principle represents a good way of identifying classes during the design phase of an application and it reminds you to think of all the ways a class can evolve. A good separation of responsibilities is done only when the full picture of how the application should work is well understand.

类的复杂性降低,实现什么职责都有清晰明确的定义;可读性提高,可维护性提高,变更的风险降低。

接口隔离原则

Interface segregation Principle: Clients should not be forced to depend upon interfaces that they don’t use.

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

The dependency of one class to another one should depend on the smallest possibleinterface.

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

intent

实例接口Object Interface,java中声明一个类,然后用new关键字产生一个实例,它是对一个类型的事物所具有的方法特征的描述,仅是一种逻辑上的抽象。

类接口 Class Interface 指在java中使用interface严格定义的接口,如下:

  • 一个接口代表一个角色,不应当将不同的角色都交给一个接口。没有关系的接口合并在一起,形成一个臃肿的大接口,这是对角色和接口的污染。
  • 不应该强迫客户依赖于它们不用的方法。接口属于客户,不属于它所在的类层次结构,即不要强迫客户使用它们不用的方法,否则这些客户就会面临由于这些不使用的方法的改变所带来的改变。

接口隔离原则核心是约束接口、降低类对接口的依赖性。遵循接口隔离原则,可将臃肿的接口细分为粒度较小的接口,预防外来变更的扩散,提高系统的灵活性和可维护性。接口隔离提高了系统的内聚性,减少了对外交互,降低系统的耦合性,如果接口粒度大小定义合理很难把握,能够提高系统的稳定性,接口过多导致数量剧增,粒度大接口少灵活性又会降低,无法提供定制服务,给整体项目带来无法预料的风险。

conclusion

If the design is already done fat interfaces can be segregated using the Adapter pattern.

Like every principle Interface Segregation Principle is one principle which require additional time and effort spent to apply it during the design time and increase the complexity of code. But it produce a flexible design. If we are going to apply it more than is necessary it will result a code containing a lot of interfaces with single methods, so applying should be done based on experience and common sense in identifying the areas where extension of code are more likely to happens in the future.

接口隔离和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装思想。单一职责注重的是职责,接口隔离注重的是对借口依赖的隔离;单一职责主要是约束类,针对程序中的实现和细节,接口隔离约束接口,针对抽象和程序整体框架的构建。

依赖倒置原则

Dependence Inversion Principle: High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.

高层模块不应该依赖低层模块,两者都依赖其抽象; 抽象不依赖细节;细节应该依赖于抽象。

intent

依赖倒置核心是面向接口编程,不要面向实现编程。采用依赖倒置原则可以减少类间的耦合性,提高系统的稳定性,降低并行开发引起的风险,提高代码的可读性和可维护性

  • 通过接口传递实现依赖

  • 通过构造函数实现依赖传递

  • 通过setter方法实现传递

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

conclusion

When this principle is applied it means the high level classes are not working directly with low level classes, they are using interfaces as an abstract layer. In this case instantiation of new low level objects inside the high level classes(if necessary) can not be done using the operator new. Instead, some of the Creational design patterns can be used, such as Factory Method, Abstract Factory, Prototype.

The Template Design Pattern is an example where the DIP principle is applied.

Of course, using this principle implies an increased effort, will result in more classes and interfaces to maintain, in a few words in more complex code, but more flexible. This principle should not be applied blindly for every class or every module. If we have a class functionality that is more likely to remain unchanged in the future there is not need to apply this principle.

底层模块尽量有抽象类或接口,变量的声明类型尽量是抽象类或接口,如此在变量的引用和实际对象间存在一个缓冲层,利于程序的扩展和优化。任何类都不应该从具体类派生,尽量不要覆写基类的方法,使用继承时需遵守里氏替换原则。

里氏替换原则

Liskov’s Substitution Principle:Derived types must be completely substitutable for their base types.

1.If for each object o1 of type S there is an object o2 of type T such thatfor all programs P defined in terms of S,the behavior of P is unchangedwhen o1 is substituted for o2 then T is a subtype of S.

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

2.Functions that use pointers or references to base classes must be ableto use objects of derived classes without knowing it.

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

intent

只要父类能出现的地方子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道父类还是子类;但是反过来则不可以,有子类的地方,父类未必就能适应。在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法。

在设计模式中体现里氏替换原则的有如下几个模式:

■ 策略模式■ 组合模式■ 代理模式

Conclusion

This principle is just an extension of the Open Close Principle and it means that we must make sure that new derived classes are extending the base classes without changing their behavior.

里氏替换主要阐述了有关继承的一些原则, 即何时使用继承,何时不该使用继承,里氏替换原则就是继承复用的基础,反映基类与子类之间的关系,是对开闭原则的补充,是实现抽象化的具体步骤的规范。通俗讲,子类可以拓展父类的方法,但不能改变父类原有的功能(尽量不要覆写)。

开闭原则

Open Closed Principle :Software entities like classes, modules and functions should be open for extension but closed for modifications.

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

intent

开闭原则是最基础的原则,起到总的指导作用,其他原则(单一职责、里氏替换、依赖倒置、接口隔离、迪米特法则)都是开闭原则的具体形态,即其他原则都是开闭原则的手段和工具。开闭原则可提高代码的复用性,粒度越小,被复用的可能性越大。

Conclusion

Like every principle OCP is only a principle. Making a flexible design involves additional time and effort spent for it and it introduce new level of abstraction increasing the complexity of the code. So this principle should be applied in those area which are most likely to be changed.

There are many design patterns that help us to extend code without changing it. For instance the Decorator pattern help us to follow Open Close principle. Also the Factory Method or the Observer pattern might be used to design an application easy to change with minimum changes in the existing code.

通过“抽象约束、封装变化”实现开闭原则, 通过接口或抽象类为软件实体定义一个相对稳定的抽象层,将相同的可变因素封装在相同的具体类中。软件中易变的细节可通过从抽象派生来实现类的拓展,当软件需要发生变化时,只需根据需求重新派生实现类来扩展即可。

迪米特原则

Demeter Principle:Only talk to your immediate friends;don’t talk to strangers.

只与你直接的朋友们通信,不要跟“陌生人”说话。

intent

直接朋友?当前对象本身、当前对象的成员对象、当前对象所创建的对象、当前对象的方法参数等,即与当前对象存在关联、组合或聚合关系,可以直接访问这些对象的方法。

只依赖应该依赖的对象,只暴露应该暴露的对象。迪米特原则的使用能够降低类间的耦合度,提高系统的复用性和扩展性,但是滥用又会造成大量的中介者,从而增加此系统复杂性,使模块间的通信效率降低。

在设计模式中,对迪米特法则进行应用的设计模式有如下两个:■ 外观模式■ 中介者模式

Conclusion

  • 在类的划分上,应该创建弱耦合的类,类与类之间的耦合越弱,越有利于实现可复用的目标。
  • 在类的结构设计上,尽量降低类成员的访问权限。
  • 在类的设计上,优先考虑将一个类设为不变类。
  • 在对其他类的引用上,将引用其他对象的次数降至最低。
  • 不暴露属性成员,而选择提供相应的访问器(getter)。
  • 谨慎使用序列化功能(Serializable)。

合成复用原则

Composite Resuse Principle

intent

在软件复用时,尽量优先使用合成、聚合等关联关系来实现,而其次才考虑使用继承关系,使用继承时务必遵循里氏替换原则,合成复用和里式替换相辅相成,都是开闭原则的具体实现规范。

通常类的复用分为继承复用和合成复用,继承复用简单易实现,但会破坏类的封装性,因为继承会将父类的实现细节暴露给子类,父类对子类却是透明的。继承使子类与父类的耦合度变高,父类的实现任何改变都会引起子类的实现发生变化,不利于扩展与维护。继承限制了复用的灵活性,从父类继承而来的实现是静态的,在编译时已经定义,在运行时不可能发生变化。合成复用维持了类的封装性,因为对象的内部细节对新对象是不可见的,新旧类之间的耦合度低,复用的灵活度高,新对象可以动态地引入与成分对象类型相同的对象。

Conclusion

尽量使用组成、聚合,少用继承。

最后和读了

开闭原则是总纲,它告诉我们对修改关闭,对扩展开放;里氏替换原则告诉我们不要破坏类的继承体系;依赖倒置原则告诉我们要面向接口编程;单一职责原则告诉我们实现类要职责单一化;接口隔离原则告诉我们在设计接口时要精简单一;迪米特原则告诉我们要降低耦合度;合成复用原则告诉我们要优先使用组合和聚合关系复用,少用继承复用。

《设计模式之禅》

《软件设计模式》java版

《图解设计模式》

《oodesign》

End: 向美好看齐,向明天说你好。

哦吼是一首歌。
Built with Hugo
Theme Stack designed by Jimmy