学习资料主要参考: 《Head First 设计模式》
设计模式是复用经验。
面对需求的增加时,改如何修改代码?
继承的一些缺点
- 代码在多个子类重复
- 很难在超类中定义所有行为
- 运行时不易改变
- “牵一发动全身”。
使用接口呢?
可以定义不同类型的接口,来表示不同的行为。
虽然可以摆脱一部分继承会导致问题(比如子类必须实现父类的抽象方法),但是它引入了新的问题:代码无法复用。
如果多个子类都拥有同一种行为,那么在这些子类中接口实现代码就要重复很多次。
那什么才是个好方法呢?
软件开发的不变真理
就是 CHANGE!
不管当初设计的多好,都需要随着时间而成长和改变。
书中遇到的第一个设计原则:
找出应用中可能需要变化之处,把它们独立出来,不要和不需要变化的混在一起。
几乎所有设计模式背后的精神所在都是它:“把会变化的部分取出并封装起来,以便以后可以轻松地改动或扩充此部分,而不需要影响其他不需要变化的部分”。
分开变化和不变化的部分!
将变化的部分,抽离出来,成为一些新的接口或者类。
针对接口编程
第二个设计原则:
针对接口编程,而不是根据实现编程。
以前的做法,要么是子类实现继承于父类的抽象方法,要么是子类实现定义的接口。这两种方法都是依赖于“实现”。现在,把易变部分抽离出来后,就由行为类来实现行为接口,而不是依赖子类实现。
“针对接口编程” 的真正意思是“针对超类型(supertype)编程”。
在不涉及Java Interface 时,“针对接口编程” ,关键就在于多态。 针对超类型编程,执行时就可以根据实际情况执行到真正的行为,不会被绑死在超类的行为上。
“针对超类型编程”,这句话更明确地可以说成:“变量的声明类型应该是超类型的,通常是一个抽象类或者一个接口,因此,只要是这个超类型的子类,都可以作为参数传入。这就意味着声明类时无需关心以后传入什么参数。”
// 定义
public interface Animal {
void makeSound();
}
class Dog implements Animal{
@Override
public void makeSound() {
System.out.println("bark.");
}
}
class Cat implements Animal{
@Override
public void makeSound() {
System.out.println("meow.");
}
}
// 调用
...
Animal a = new Dog();
a.makeSound();
...
以上的行为换句话说,就是原先需要父类定义的行为,“委托”给了别处实现。
封装行为的大局观
重点在于类之间的关系,是“IS-A(是一个)”的关系,还是“HAS-A(有一个)”的关系。
“有一个” 关系可能比“是一个”更好。
“有一个” 的关系不是继承而来的,而是通过“组合”而来。这就引出了第三条设计原则:
多用组合,少用继承。
使用组合建立的系统更有弹性,不仅可以将算法封装为类,更可以“在运行时动态地改变行为”。
第一个设计模式
以上提到的其实就是:策略模式(Strategy Pattern)。
它的定义是:定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。
共享模式词汇的威力
- 以更少的词做更充分的沟通
- 将说话的方式保持在模式层次,可以让你待在“设计圈子”久一点
- 可以帮助开发团队快速充电
- 可以帮助初级开发人员迅速成长
如何使用设计模式
设计模式不会直接进入我们的代码中,它们首先要在我们的“大脑”中,然后在根据自己特定的应用,在原有设计模式上做一些取舍,最后应用到我们代码中。