《Head First 设计模式》

243 阅读6分钟

OO基础:抽象、封装、继承、多态

OO设计目标:可复用、可扩充、可维护

设计原则

  • 封装变化:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
  • 针对接口编程,而不是针对实现编程。
    • 针对接口编程,关键在于多态。变量的声明类型设置为超类,即抽象类或接口,声明类时不必理会以后执行时的真正对象类型。
  • 多用组合,少用继承。
  • 为了交互对象之间的松耦合设计而努力。
  • 类应该对扩展开放,对修改关闭。
  • 依赖倒置原则:要依赖抽象,不要依赖具体类。
  • 最少知识原则:只和你的密友谈话。
    • 要减少对象之间的交互。(参考外观模式,客户不需要和许多子系统直接接触,通过外观直接使用)
  • 好莱坞原则:别调用我们,我们会调用你。(高层组件对底层组件的态度)
  • 单一责任原则:一个类应该只有一个引起变化的原因。


策略模式

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

(自己哼唧:算法族即为某个功能的多种实现方式 = 超类<抽象类或接口>的多种实现,客户持有超类的引用,可以指向不同的实例<互相替换>,算法变化的时候客户代码不需要修改)

课本Demo:

背景:模拟鸭子游戏中,有绿头鸭、红头鸭、橡皮鸭、鸭鸣器...等各种各样的鸭子,这些鸭子都有重量等基本信息,除此之外,有的鸭子会叫且叫声不一样,有的鸭子会飞,即有不一致的行为。

实现方案A:父类Duck中定义鸭子所有的属性和行为,子类可以重写不一致的方法

  • 此方案的缺点:
    • 改变牵一发而动全身,造成其他鸭子不想要的改变
    • 代码在多个子类中重复
    • 运行时的行为不容易改变
    • 很难知道所有鸭子的全部行为

实现方案B:父类Duck中定义鸭子共有的属性和行为,特有的行为定义为接口,需要的鸭子类实现对应的接口

  • 此方案的缺点:
    • 代码无法复用
    • 行为实现后不便于改变(eg:受到某种外界刺激后,飞行方式由上下飞要变成左右飞...)

最终实现方案:父类Duck中定义鸭子所有的属性和行为(内部实现靠接口引用),特有的行为定义为接口,各种实现方式定义为实现对应接口的行为类,父类Duck中持有行为的接口引用,子类将接口引用指向具体的行为类。




观察者模式

定义了对象之间的一对多依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

  • 我们经常用的接口回调一般都是一对一,也算是观察者模式吧


装饰者模式

动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性地替代方案。

(自己哼唧:类似递归)


工厂模式

定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。


抽象工厂模式

提供一个接口,用于创建相关或依赖对象的家族,而不需要明确指定具体类。


单例模式

确保一个类只有一个实例,并提供一个全局访问点。

* 需要注意线程安全的问题,synchronized方法、static实例变量初始化(预加载,饿汉模式)、double-checked locking(volatile关键字);

* 如果使用多个类加载器,可能导致单例失效而产生多个实例;

* 如果使用JVM1.2及之前的版本,必须建立单例注册表,以免垃圾收集器将单例回收。


命令模式

将“请求”封装成对象,以便使用不同的请求、队列或者日志来参数化其他对象。命令模式也支持可撤销的操作。


适配器模式

将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。(eg:三孔插座转换为两孔插座)

对象适配器:组合。实现目标接口,持有被适配者对象,将方法委托给被适配者对象。

类适配器:多重继承,Java不支持

装饰者模式:不改变接口,但加入责任。
适配器模式:将一个接口转换成另一个接口。
外观模式:让接口更简单。提供一个简化接口,但依然将系统完整的功能暴露出来。


外观模式

提供了一个统一的接口,用来访问子系统中的一群接口。外观定义了一个高层接口,让子系统更容易使用。(大象进冰箱有一系列步骤,把它统一在一个接口中,用户只需要调用一个方法即可实现,不必挨个实现相关的接口方法)

* 简化接口,调用方便。基础功能仍然存在,需要的时候调用基础功能实现

* 和命令模式的区别?(外观模式主要是为了调用方便,将一些功能合并在一个方法内;命令模式的话,是有一个命令对象,调用者进行操作后触发命令对象的execute方法,命令对象对应的接收者的动作就会被调用)


模版方法模式

在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。(某类事物某种功能的算法模版,骨架不变,具体的子类实现可能会有差异,通过继承父类实现抽象方法/重写可继承的方法实现个性化)

* 模版方法一般声明为final,以免子类改变这个算法的实现。

* 不变的算法骨架,抽象父类,子类继承父类,通过 “实现抽象方法/重写可继承方法 ”实现个性化


迭代器与组合模式

迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示。

组合模式:允许你将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。


状态模式

允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它的类。


代理模式

为另一个对象提供一个替身或占位符以控制对这个对象的访问。