Walt You - 行是知之始

《HeadFirst设计模式》学习日志(一):入门

2019-02-22


学习资料主要参考: 《Head First 设计模式》



设计模式是复用经验

面对需求的增加时,改如何修改代码?

继承的一些缺点

  1. 代码在多个子类重复
  2. 很难在超类中定义所有行为
  3. 运行时不易改变
  4. “牵一发动全身”。

使用接口呢?

可以定义不同类型的接口,来表示不同的行为。

虽然可以摆脱一部分继承会导致问题(比如子类必须实现父类的抽象方法),但是它引入了新的问题:代码无法复用

如果多个子类都拥有同一种行为,那么在这些子类中接口实现代码就要重复很多次。

那什么才是个好方法呢?

软件开发的不变真理

就是 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)。

它的定义是:定义算法族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化独立于使用算法的客户。

共享模式词汇的威力

  • 以更少的词做更充分的沟通
  • 将说话的方式保持在模式层次,可以让你待在“设计圈子”久一点
  • 可以帮助开发团队快速充电
  • 可以帮助初级开发人员迅速成长

如何使用设计模式

设计模式不会直接进入我们的代码中,它们首先要在我们的“大脑”中,然后在根据自己特定的应用,在原有设计模式上做一些取舍,最后应用到我们代码中。


Content