设计模式-六大设计原则(二)

开放-封闭原则

开放-封闭原则是面向对象开发中中所有设计原则的核心。在面向对象编程时,如果要添加一个新的功能,添加一个新类来完成往往要比修改现有的类更加方便和安全。

所谓添加而不修改,原因是软件设计要求追求的目标是封装变化、降低耦合,而开放-封闭原则正是对这一目标的最直接的体现。对于软件设计者来说,应该在不需要对原有的系统进行修改的情况下,来实现更加灵活的系统拓展。

开发-封闭原则的定义是:程序的实体对象(模块、类、函数等)应该可以进行拓展,但是不应该可以修改。有两个特征:

对于拓展是开放的
对于修改是封闭的

开放-封闭原则提供了一个使系统面对需求变更时,可以保持系统相对稳定的解决方案。

举个例子

猫类是动物类的子类,所有动物会呼吸,而猫会抓老鼠。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
//动物类
public class Animal{
public void Breath(){
//呼吸的方法
}
}
//猫类
public class Cat extents Animal{
public void CatchMouse(){
//抓老鼠的方法
}
}
//对于
public static void main(String[] args){
Cat cat = new Cat();
cat.Breath();
cat.CatchMouse();
}

猫类有两个方法呼吸和抓老鼠,但是当业务发生改变时,例如一只叫做咪咪的猫还会爬树,这里根据开放封闭原则。

1
2
3
4
5
public class Mimi extends Cat{
public void Ctree(){
//爬树的方法
}
}

依赖倒转原则

当一个高层类依赖与一个低层类,如果低层发生改变,高层也要相应的发生改变。这里就需要根据依赖倒转原则来对这种现象进行解耦和,依赖倒转原则的定义是:程序的高层模块不应该依赖与低层模块,但是两者都应该依赖与抽象;抽象不应该依赖与具体细节,而细节应该依赖与抽象。字面上可能很难懂,它表达的意思差不多就是告诉我们面对对象应该针对接口编程,而不是针对实现编程。

开发中使用这个原则需要遵循以下几条规范:

  1. 每个类尽量都继承自接口或者抽象类,或者都有。是依赖倒转的基本要求,有抽象才能依赖倒转。
  2. 变量的类型尽量是接口或者抽象类。
  3. 尽量不要去覆盖基类的方法。如果基类是个抽象类,而且方法已经实现,子类就尽量不要去覆盖,覆盖了抽象方法对依赖的稳定性会有影响。

举个例子

一个十分复杂高层类Manager和一个低层类Worker,当又新建了一个低层类SeniorWorker,此时会发生什么呢?

  1. 我们需要修改Manager类。
  2. Manager部分功能可能会受到影响。
  3. Manager类需要重新做单元测试。

无依赖倒转原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//工人
class Worker{
public void work(){
//....working
}
}
//管理者
class Manager{
Work m_worker;
public void setWorker(Worker w){
m_worker = w;
}

public void manage(){
m_worker.work();
}
}
//新加入高级工人
class SeniorWorker{
public void work(){
//.......working much more
}
}

如果新加入高级工人,就需要在Manager类中加入设置高级工人的方法,如果Manager类本身就很复杂,此时再添加新代码是不可取的,下面支持了依赖倒转原则的代码。在工人基础上加入了一个抽象层的接口。这样就不需要修改Manager类了,简化了工作。

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
//抽象层
interface Iworker{
public void work();
}

//工人
class Worker implements Iworker{
public void work(){
//......working
}
}

//高级工人
class SeniorWorker implements Iworker{
public void work(){
//....working much more
}
}

//管理员
class Manager{
Iworker m_worker;

public void setWorker(Iworker w){
m_worker = w;
}

public void manage(){
m_worker.work();
}
}

以后如果需要添加新的工种,只需实现工人接口就可以了,Manager类完全不需要对此进行修改。