常见设计模式要点总结

前言

最近在看《head first 设计模式》,发现每个章节后的要点总结都是言简意骇,所以特写此篇博客对常见的设计模式要点做个总结。
<!– more –>

观察者模式

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

  • 观察者模式定义了对象之间一对多的关系
  • 主题(可观察者)用一个共同对接口来更新观察者
  • 被观察者不知道观察者的细节,只知道观察者实现了观察者接口
  • 多个观察者时,不可以依赖特定的通知顺序

 ●  抽象主题(Subject)角色:抽象主题角色把所有对观察者对象的引用保存在一个聚集(比如ArrayList对象)里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象,抽象主题角色又叫做抽象被观察者(Observable)角色。

  ●  具体主题(ConcreteSubject)角色:将有关状态存入具体观察者对象;在具体主题的内部状态改变时,给所有登记过的观察者发出通知。具体主题角色又叫做具体被观察者(Concrete Observable)角色。

  ●  抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到主题的通知时更新自己,这个接口叫做更新接口。

  ●  具体观察者(ConcreteObserver)角色:存储与主题的状态自恰的状态。具体观察者角色实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态 像协调。如果需要,具体观察者角色可以保持一个指向具体主题对象的引用。

装饰者模式

动态的将责任加到对象上,想要扩展功能,装饰者提供有别于继承的另一种选择

  • 装饰者模式意味着一群装饰者类,这些类用来包装具体组件
  • 装饰者类都经过接口或继承实现
  • 可以用无数个装饰者包装一个组件
  • 装饰者会导致设计中出现许多小对象,过度使用会让程序复杂

在装饰模式中的角色有:

  ●  抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。

  ●  具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类。

  ●  装饰(Decorator)角色:持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口。

  ●  具体装饰(ConcreteDecorator)角色:负责给构件对象“贴上”附加的责任。

工厂模式

简单工厂:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。

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

  • 所有的工厂都是用来封装对象的创建
  • 工厂方法使用继承:把对象的创建委托给子类,子类实现工厂方法来创建对象
  • 抽象工厂使用对象组合:对象的创建被实现在工厂接口所暴露出来的方法中
  • 抽象工厂创建相关的对象家族,不需要依赖他们的具体类
  • 依赖倒置原则,依赖于抽象而非具体类型

下图是简单工厂模式的uml图

《常见设计模式要点总结》

简单工厂的关注点是产品,如上图中的CpuFactory,MainboardFactory。当我们需要新增一个产品的时候(例如memory 就不需要对原有代码进行修改),但是当我们需要新增一种cpu的时候(例如huawei cpu)简单工厂就需要对原有代码改动了,于是我们引入第二种抽象工厂。

《常见设计模式要点总结》抽象工厂的关注点是产品族,如上图中的IntelFactory,AmdFactory。当我们需要新增一个产品族的时候(例如HuaweiFactory 就不需要对原有代码进行修改),但是当我们需要新增一种产品的时候(例如memory)抽象工厂就需要对原有代码改动了。

以上两种工厂模式,各有优劣。

单例模式

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

  • 单例模式确保程序中一个类最多只有一个实现
  • 单例模式提供访问者合格实例对全局访问点
  • Java中实现单例模式需要私有构造器, 一个静态方法和一个静态变量
  • 必须假设所有的程序都是多线程的,考虑并发的问题
  • 如果使用多个类加载器,可能导致单例模式失效产生多个实例

推荐一种单例模式的最佳实践

public class SingleTon {
    private SingleTon(){}
    
    private static class InstanceHolder{
        private final static SingleTon singleTon = new SingleTon();
    }
    
    public SingleTon getSingleTon(){
        return InstanceHolder.singleTon;
    }
}

适配器模式/门面模式

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

门面模式:提供了一个统一的接口用来访问子系统的一群接口。外观定义了一个高层接口使得子系统更加易用

  • 当需要使用一个现有的类而其接口并不符合你的需要时,使用适配器
  • 适配器将一个对象包装起来以改变其接口,装饰者将一个对象包装起来以增加新的行为和责任,门面模式将一群对象“包装”简化其接口
  • 当需要简化并同意一个很大的接口或者一群复杂的接口时使用门面模式
  • 门面模式可以从一个复杂的子系统中解耦
  • 使用一个门面模式需要将子系统组合进外观中,然后将工作委托给子系统执行

适配器uml图

模式所涉及的角色有:

  ●  目标(Target)角色:这就是所期待得到的接口。注意:由于这里讨论的是类适配器模式,因此目标不可以是类。

  ●  源(Adapee)角色:现在需要适配的接口。

  ●  适配器(Adaper)角色:适配器类是本模式的核心。适配器把源接口转换成目标接口。显然,这一角色不可以是接口,而必须是具体类

门面模式相对比较简单

《常见设计模式要点总结》

上图是我暑假在阿里实习做的一个小需求。其中核身组件就用到了门面模式,将核身组件这个领域对象暴露给前端,使得前端不必关注具体的每个核身项,从一个复杂的子系统中解耦。

代理模式

一个替身或占位符以访问这个对象

  • 代理模式为另一个对象提供代表,以便控制客户对对象的访问
  • 代理在结构上类似装饰者但目的不同
  • 装饰者模式为对象加上行为,而代理则是控制访问

在代理模式中的角色:

  ●  抽象对象角色:声明了目标对象和代理对象的共同接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

  ●  目标对象角色:定义了代理对象所代表的目标对象。

  ●  代理对象角色:代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或之后,执行某个操作,而不是单纯地将调用传递给目标对象。

总结

想要学习设计模式的初衷是,如何写出更灵活,更健壮,更符合规范的代码。也确实从设计模式的学习中感受到了面向对象的强大,不过纸上得来终觉浅,绝知此事要躬行。

参考文档:

《Head First 设计模式》

    原文作者:设计模式
    原文地址: https://segmentfault.com/a/1190000016828995
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞