设计模式学习笔记(一)

设计模式学习笔记

学习设计模式使用的书本为《head first 设计模式》
根据教材写的各模式的示例代码放在GitHub上,后续会将仓库地址放上来。

一、设计原则

设计原则:

  • 变化部分原则:找出应用中可能需要变化之处,把它们独立出来,不要和不需要变化的代码混在一起。

  • 接口原则:针对接口编程,而不是针对实现编程。

    • 这里的“接口”指的是“超类型”,可以是Java接口和抽象类。利用Java多态特性,只要是具体实现了该超类型的类所产生的对象,都可以指定给这类变量。即:子类对象可以赋值给父类变量。
  • 组合原则:多用组合,少用继承

    • 组合(有一个),每一个鸭子有一个FlyBehavior。继承(是一个),一个鸭子是一个能fly的类。
  • 松耦合原则:为了交互对象之间的松耦合设计而努力

    • 松耦合:改变两类对象中的一方不会影响另一方,只要它们之间的接口仍被遵守,就可以自由地改变。
  • 开放-关闭原则:类应该对拓展开放,对修改关闭。

  • 依赖倒置原则:要依赖抽象类,不要依赖具体类

    • 变量不可以持有具体类的引用
    • 不要让类派生自具体类
    • 不要覆盖类中已经实现的方法
  • 最少知识原则:只和最接近的对象交互,尽量减少对象之间的交互

  • 好莱坞原则:低层组件别调用高层组件,高层组件会在需要时调用低层组件。

  • 单一责任原则:尽量让每个类保持单一责任,一个类应该只有一个引起变化的原因。

设计目标:

  • 可复用
  • 可扩充
  • 可维护

二、策略模式

定义:

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

​一个目标物件管理所有相依于它的观察者物件,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实现事件处理系统。

个人理解:

​将可能产生变化的部分方法(鸭子的fly行为)封装起来,成为一个接口(FlyBehavior)。而后对于一些具体的实现,创建相应的类(FlyWithWings)。并在使用类(Duck)中加入一个私有的接口类型(FlyBehavior)变量,在特定的时候将该变量赋值为具体的对象。

三、观察者模式

定义:

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

个人理解:

​以报纸订阅为例。使用一个接口(接口1)代表对观察者的控制,其中定义注册、删除和更新所有观察者方法。使用另一个接口(接口2)表示观察者,其中定义更新方法。观察者类实现接口2,实现特定的更新方法。而主题类实现接口1,并包含一个观察者接口列表。

​当注册、删除时,向该观察者接口列表增删对象。当更新时,循环调用每一个观察者接口对象的更新方法。

四、装饰者模式

定义:

​在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。

个人理解:

​还是依赖于Java中父类变量可以指向子类对象的特性,通过声明一个统一的基类,然后通过这个基类派生出特定的主题类以及各种装饰器类。然后在装饰器中定义一个父类变量,再将被装饰的主题类赋值给这个变量,从而可以在装饰器中调用主题类的方法,通过对这些方法的覆盖,达到装饰的效果。

​因为共有同一个父类,故装饰后的装饰器类可以在需要主题类的位置替代出现。但是同样存在一定的局限性,那就是只能以父类的形式使用,不能以想要的特定主题类使用。

五、工厂模式

定义:

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

个人理解:

​工厂模式定义了两个接口(接口或抽象类),一个产品接口、一个工厂接口。其中通过实现产品接口定义具体的产品类,通过实现工厂接口定义具体的工厂类。

​通过这样的模式,能给与子类一定的自由,如:工厂类生产何种产品,产品类的属性、如何初始化等。但同时也能对子类的一定部分进行约束,如:工厂类中如何加工产品等。

六、单例模式

定义:

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

个人理解:

​通过将类的构造函数定义成私有函数,然后声明一个公有全局函数构造和获取唯一的实例。

​该模式可以保证数据库连接、缓存等对象为唯一的。节约资源以及确保程序安全。

问题及解决方案:

​当使用单例模式时,一旦设计到多线程,可能导致单例模式被破坏。

  1. 可以使用"急切"创建实例,即一开始就初始化单例对象。

  2. 可以使用“双重检查加锁”

七、命令模式

定义:

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

个人理解:

​定义一个 “命令”接口,然后创建不同的命令类—实现“命令”接口,命令类将接口中的方法实现—通过调用实体类的方法。然后控制类通过设置对应的命令接口对象,可以实现控制类中的方法在赋值了不同的命令接口对象时,可以完成不同动作。

​如:一个拥有7个按钮的万能遥控器,通过设置不同的命令对象,可以使这七个按钮完成特定的动作。设置开灯命令对象时,按钮可以完成开灯动作等。

八、适配器模式与外观模式

(一)适配器模式

定义:

​将一个类的接口,转换成客户期望的另一个接口。适配器可以让原本接口不兼容的类可以合作无间。

个人理解:

​当一个某种场景需要A类对象作为参数,而实际参数却是属于B类。此时需要一个适配器将B类参数适配为A类。此时,可以定义一个适配器类—继承A类,并包含一个B类对象(或直接继承A、B类)。则,该适配器类即可用于A类对应的场景,又完成了B类的资源的调用。即实现了B类在A类场景的使用。

(二)外观模式

定义:

​提供了一个统一的接口,用来访问子系统种的一群接口。外观定义了一个高层接口,让子系统更容易使用。

个人理解:

​一个系统可能拥有多个部分、多个类、多个接口。有时一个完整的功能可能涉及到这个系统的多个部分,一个个调用可能比较麻烦,所以通过外观模式对这些部分进行一个统一封装,封装成一个统一的接口,简化这个过程。但是同时也不会妨碍对那些部分的访问和调用,只是提供一个更方便的接口。

九、模板方法模式

定义:

​在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。

个人理解:

​父类中的一个方法实现了骨架,其中的一些部分被封装成抽象方法或普通方法。允许子类实现父类的这些抽象方法或覆盖普通方法。其中抽象方法实现了子类定义算法的某些步骤。

​其中覆盖的普通方法,称为钩子方法。钩子方法可以实现子类对父类定义的模板方法的控制。

十、迭代器与组合模式

(一)迭代器模式

定义:

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

个人理解:

​当有两种或两种以上的集合(数组、队列…)需要用于同一场合,可以通过申明一个拥有遍历集合功能的方法的迭代器接口,然后通过实现这个接口创建每个集合类的特定迭代器类。然后通过该迭代器类,即可对不同的集合类使用相同的方法(hasNext、next)进行遍历。

(二)组合模式

定义:

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

设计模式学习笔记(一)_第1张图片

个人理解:

​如上图所示,当一个集合的元素既可能是元素项,也可能是另一个集合 — 即结构可能为树形时。通过定义一个共有的component接口,其中定义集合中元素项、集合项可能用到的方法。然后根据该接口派生出元素项类和集合项类。

​其中,元素项(叶子节点)包含自己的属性、实现自身需要的方法。集合项(组合节点)包含属性以外,还包含一个component对象数组,存储该集合的元素。并实现集合项需要的方法。当需要遍历时,组合节点遍历自身所有节点,并调用每个节点对应方法。

你可能感兴趣的:(学习笔记)