设计模式开篇之设计原则

Posted by 程序亦非猿 on 2015-09-06

前言

PS:本人边学边记录,所以可能有欠缺有错误有不足之处,还望指导!

在学习设计模式之前我们有必要先了解一下一些设计原则.
其实设计原则也是从设计模式里来的,所以暂时不需要太理解,毕竟光看原则可能有时候理解不了.

SOLID设计原则)

讲设计原则,则不得不先提一下SOLID设计原则.
它的每个字母分别代表一个原则,接下来分别介绍一下.

单一职责原则(SRP)

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

a class should have only a single responsibility (i.e. only one potential change in the software’s specification should be able to affect the specification of the class)

简单来说就是:一个类应该只有一个职责(只有一个潜在的改变能影响这个类);

每一个引起类变化的原因就是一个职责,当类具有多职责时,应该把多余职责分离出去,分别创建类来完成,
否则这个类的耦合度会不断提升,不利于维护等.

比如某些所谓的多功能道具,集多少多少功能于一体,吹得很牛逼,结果呢?其中一个坏了,整个都坏了,全完蛋.

如果说我们的代码也这样,一个类又有Http请求又有IO操作的方法又封装了各种Util方法,背负各种职责,耦合度高得能吓死你,还怎么快乐地敲代码?

SRP的优点很明显:高内聚,低耦合,类结构逻辑清晰明了,提高了可读性,同时也易于维护

开闭原则(OCP)

开闭原则(Open Closed Principle)

“software entities(classes, modules, functions, etc.) should be open for extension, but closed for modification.”

实体(类,模块..等)应该对扩展开放,对修改关闭.
也就是说实体可以做到不修改源代码就可以实现功能扩展.

比如我们实现了功能A,测试完后发布.后来我们需要增加功能,在不得已的情况下我们最好是对原有的代码功能实现扩展,而不是去修改原来的代码.
因为原来的代码经过了测试,而我们再次去修改很有可能破坏原来的代码,或者带来Bug,所以我们需要对修改关闭.

做到开闭原则可以做到稳定,可扩展

But,臣妾表示做不到啊!

里氏代换原则(L)

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

It states that, in a computer program, if S is a subtype of T, then objects of type T may be replaced with objects of type S (i.e., objects of type S may substitute objects of type T) without altering any of the desirable properties of that program (correctness, task performed, etc.).

简单来说就是:父类可以出现的地方,子类也可以出现,父类都可以被子类代替而无需改动.

其实这原则就是运用了继承,多态的特性,在很多设计模式中都有体现.

其实这个原则要求我们做的也很好理解,这么做就可以用一个方法符合所有T的类型,节省代码.

接口隔离原则(ISP)

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

(ISP) states that no client should be forced to depend on methods it does not use.

客户端不应该被强迫地依赖那些根本用不上的方法.
什么意思?
假设有个接口A,A有三个方法,而我们的类B需要其中的某一个,如果让B实现A那么B就会多依赖两个用不上的方法,这就违背了该原则.
另外这么做还有另外一个非常大的隐患,如果我们改变了A的其他两个方法,那么会影响到B.

在Java源码中我们可以找到很多接口都只有一个方法,比如:

1
2
3
4
5
6
7
public interface AutoCloseable {
void close() throws Exception;
}
public interface Comparable<T> {
int compareTo(T another);
}

其实原因就在这个接口隔离原则上.

ISP is intended to keep a system decoupled and thus easier to refactor, change, and redeploy.

接口隔离原则优点:

  1. 让我们的程序解耦,更容易重构,改变,重新部署.

另外个人觉得接口隔离原则跟SRP其实挺类似,它也可以提高内聚,降低耦合,提升可读性~

依赖倒置原则(DIP)

依赖倒置原则(Dependency Inversion Principle)

the dependency inversion principle refers to a specific form of decoupling software modules. When following this principle, the conventional dependency relationships established from high-level, policy-setting modules to low-level, dependency modules are inverted (i.e. reversed), thus rendering high-level modules independent of the low-level module implementation details.

简单说就是:高级模块独立于低级模块的实现细节.

DIP指明了:

  1. 高级模块不应该依赖低级模块,它们都应该依赖于抽象.
  2. 抽象不应该依赖细节.细节应该依赖于抽象.

其他必须知道的原则

DRY

Don’t repeat yourself.
不要重复自己,也许你听过很多次,但它绝不是复制黏贴那么简单.

优先使用组合,少用继承

在EffectiveJava 和HeadFirstDesignPattern里不止一次看到优先使用组合的建议.
继承的缺点可不少.

针对接口编程,而不是实现

这里的接口指interface抽象.

封装变化

把经常变化的代码封装起来,与不变的代码隔离开.

迪米特法则

迪米特法则 (Law of Demeter Principle),也称为“最少知识原则(Principle of Least Knowledge)
wiki百科的解释挺好的,我就照搬过来了,如下:

  1. 每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元;
  2. 每个单元只能和它的朋友交谈:不能和陌生单元交谈;
  3. 只和自己直接的朋友交谈。

很多面向对象程序设计语言用”.”表示对象的域的解析算符,因此得墨忒耳定律可以简单地陈述为“只使用一个.算符”。 因此,a.b.Method()违反了此定律,而a.Method()不违反此定律。
一个简单例子是,人可以命令一条狗行走(walk),但是不应该直接指挥狗的腿行走,应该由狗去指挥控制它的腿如何行走。

  • 优点

使得软件更好的可维护性与适应性。
因为对象较少依赖其它对象的内部结构,可以改变对象容器(container)而不用改变它的调用者(caller)。

总结

如果我们的目标是:Reliable,Scalable,Maintainable.,那么设计原则可以帮助我们实现,学习理解设计原则对编码大有裨益!~
理论需要与实际结合,多在写代码的时候考虑一下,对提高代码质量有很大的帮助~
好了,这次就写那么一点点,如有错误,欢迎批评指正,也欢迎交流!

推荐书籍

HeadFirstDesignPattern.
Effective Java.

参考/更多

http://colobu.com/2015/03/05/10-object-oriented-design-principles-you-should-know/
编程经验之接口分离原则
设计模式之面向对象与类基础特征概念