设计模式三:结构型设计模式与关系型设计模式
之前简单了解了设计模式的创建型模式,现在来看下几个比较常见的结构型设计模式与关系型设计模式
适配器模式
适配器模式:将一个接口转换成客户希望的另一个接口,使接口不兼容的那些类可以一起工作。它可以让原本两个不兼容的接口能够无缝完成对接。作为中间件的适配器将目标类和适配者解耦,增加了类的透明性和可复用性。
适配器模式中包含的角色:
Target(目标抽象类):目标抽象类定义客户所需要的接口;
Adapter(适配器类):适配器可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配,适配器类是适配器模式的核心,在对象适配器中,它通过继承Target并关联一个Adaptee对象试二者产生联系;
Adaptee(适配者类):适配者类为被适配的角色,它定义了一个已经存在的接口,这个接口需要适配。
组合模式
组合模式:组合模式组合多个对象形成树形结构以表示“整体-部分”的结构层次。它定义了如何将容器对象和叶子对象进行递归组合,使得客户在使用的过程中无须进行区分,可以对他们进行一致的处理。
组合模式包含如下角色:
Component: 抽象构件
Leaf: 叶子构件
Composite: 容器构件
Client: 客户类
外观模式
外观模式:为子系统中的一组接口提供一个统一的入口。它让一个应用程序中子系统间的相互依赖关系减少到了最少,它给子系统提供了一个简单、单一的屏障,客户通过这个屏障来与子系统进行通信。但是它违背了“开闭原则”,因为增加新的子系统可能需要修改外观类或客户端的源代码。
外观模式包含如下的两个角色:
Facade(外观角色):在客户端中可以调用它的方法,在外观角色中可以知道相关的子系统的功能和职责;
SubSystem(子系统):在软件系统中可以有一个或者多个子系统角色,每一个子系统可以不是一个类,而是一个类的集合;每一个子系统都可以被客户端直接调用,或者被外观角色直接调用;子系统并不知道外观的存在,对于子系统而言,外观角色也是一个客户端。
在标准的外观模式中并没有抽象外观类,但如何涉及到增加、删除、更换子系统类的操作,那么就会违背开闭原则,如果涉及到这些功能,可以增加抽象外观类,通过抽象外观类进行调用,根据客户端的需求实例化不同的子系统,以符合开闭原则。
代理模式
代理模式:给某一个对象提供一个代理或者占位符,并由代理对象来控制对原对象的访问。它使得客户不能直接与真正的目标对象通信。代理对象是目标对象的代表,其他需要与这个目标对象打交道的操作都是和这个代理对象在交涉。这样起到了的作用和保护了目标对象的,同时也在一定程度上面减少了系统的耦合度。
代理模式中涉及到的角色:
Subject(抽象主题角色):它声明了真实主题和代理主题的共同接口,这样一来在任何使用真实主题的地方都可以用代理主题,客户端只需要针对抽象主题角色进行编程;
Proxy(代理主题角色):它包含了对真实主题的引用,从而可以在任何时候操作真实主题对象;
RealSubject(真实主题角色)它定义了代理角色所代表的真实对象,在真实主题角色中实现了真实的业务操作,客户端可以通过代理主题角色间接调用真实主题角色中定义的操作。
//抽象主题代码 abstract class Subject { public abstract void Request(); } ... //真实主题代码 class RealSubject : Subject{ public override void Request(){ //业务方法具体实现代码 } } ... //代理主题 class Proxy : Subject{ private RealSubject realSubject = new RealSubject(); //维持一个对真实主题对象的引用 public void PreRequest(){ …... } public override void Request(){ PreRequest(); realSubject.Request(); //调用真实主题对象的方法 PostRequest(); } public void PostRequest(){ …… } }
命令模式
命令模式:将一个请求封装为一个对象,从而让我们可以用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式提供了一种降低请求发送者和接受者之间耦合度的解决方案。命令模式可以将请求的发送者和接收者之间实现完全的解耦,发送者和接收者之间没有直接的联系,发送者只需要知道如何发送请求命令即可,其余的可以一概不管,甚至命令是否成功都无需关心。
在命令模式中包含的角色:
Command(抽象命令类):抽象命令类一般是一个抽象类或者接口,在其中生命了用于执行请求的execute等方法,通过这些方法可以调用请求接受者的相关操作;
ConcreteCommand(具体命令类):具体命令类是抽象命令类的子类,实现了在抽象命令类中声明的方法,它对应具体的接受者对象,将接受者对象的动作绑定在其中;
Invoker(调用者):调用者即请求发送者,它通过命令对象来执行请求;
Receiver(接受者):接受者执行与请求相关的操作,它具体实现对请求的业务处理。
迭代器模式
迭代器模式:提供一种方法顺序访问一个聚合对象中的各个元素,而不是暴露其内部的表示。迭代器模式是将迭代元素的责任交给迭代器,而不是聚合对象,我们甚至在不需要知道该聚合对象的内部结构就可以实现该聚合对象的迭代。
在迭代器模式结构中包含如下角色:
Iterator(抽象迭代器):它定义了访问和遍历元素的接口,声明了用于遍历数据元素的方法;
ConcreteIterator(具体迭代器):它实现了抽象迭代器接口,完成了对聚合对象的遍历,同时在具体迭代器中通过游标来记录在聚合对象中所处的当前位置;
Aggregate(抽象聚合类):它用于存储和管理元素对象,声明一个createIterator方法用于创建迭代器对象,充当抽象迭代器工厂角色;
ConcreteAggregate(具体聚合类):它实现了抽象聚合类中声明的createIterator方法,该方法返回一个ConcreteIterator对象。
//抽象迭代器,声明用于遍历聚合对象中存储元素的方法 interface Iterator { public void first(); //将游标指向第一个元素 public void next(); //将游标指向下一个元素 public boolean hasNext(); //判断是否存在下一个元素 public Object currentItem(); //获取游标指向的当前元素 } //具体迭代器,实现抽象迭代器中的方法 class ConcreteIterator implements Iterator { private ConcreteAggregate objects; //维持一个对具体聚合对象的引用,以便于访问存储在聚合对象中的数据 private int cursor; //定义一个游标,用于记录当前访问位置 public ConcreteIterator(ConcreteAggregate objects) { this.objects=objects; } public void first() { ...... } public void next() { ...... } public boolean hasNext() { ...... } public Object currentItem() { ...... } } //抽象聚合类 interface Aggregate { Iterator createIterator(); } //具体聚合类,一方面负责存储数据,一方面实现在抽象聚合类中声明的工厂方法createIterator,创建对应的迭代器对象 class ConcreteAggregate implements Aggregate { ...... public Iterator createIterator() { return new ConcreteIterator(this); } ...... }
观察者模式
观察者模式:定义对象之间的一种一对多的依赖关系,使得当一个对象状态发生变化时,其相关依赖对象都会得到通知并被自动更新。
在观察者模式结构图中包含如下角色:
Subject(目标):目标又称为主题,是被观察的对象。在目标中定义一个观察者集合,一个观察目标可以有多个观察者来观察,它提供一系列方法增加和删除观察者对象,同时定义了通知方法notify;
ConcreteSubject(具体目标):具体目标是目标的子类,通常包含有经常发生改变的数据,当它的状态改变时,向各个观察者发出通知;
Observe(观察者):观察者将对观察目标的改变做出反应,观察者一般定义为接口,该接口声明了更新数据的方法update;
ConcreteObserve(具体观察者):在具体观察者中维护一个指向具体目标对象的引用,它存储具体观察者的有关状态,这些状态需要和具体目标的状态保持一致;它实现了Observe中的抽象update方法。
观察者模式描述了如何建立对象与对象之间的依赖关系,以及如何构造满足这种需求的系统。观察者模式包含观察目标和观察者两类对象,一个目标可以有任意数目的与之相依赖的观察者,一旦观察目标的状态发生改变,所有的观察者都将得到通知。这种交互也称为发布-订阅。
//抽象目标类 abstract class Subject { //定义一个观察者集合用于存储所有观察者对象 protected ArrayList observers = new ArrayList(); //注册方法,用于向观察者集合中增加一个观察者 public void attach(Observer observer) { observers.add(observer); } //注销方法,用于在观察者集合中删除一个观察者 public void detach(Observer observer) { observers.remove(observer); } //声明抽象通知方法 public abstract void notify(); } //具体目标 class ConcreteSubject extends Subject { //实现通知方法 public void notify() { //遍历观察者集合,调用每一个观察者的响应方法 for(Object obs:observers) { ((Observer)obs).update(); } } } //抽象观察者 interface Observer { //声明响应方法 public void update(); } //具体观察者 class ConcreteObserver implements Observer { //实现响应方法 public void update() { //具体响应代码 } }
策略模式
策略模式:定义一系列算法类,将每一个算法封装起来,并让它们可以相互替换,策略模式让算法独立于使用它的客户而变化
在策略模式结构图中包含如下几个角色:
Context(环境类):环境类是使用算法的角色,它在解决某个问题(即实现某个方法)时可以采用多种策略。在环境类中维持一个对抽象策略类的引用实例,用于定义所采用的策略。
Strategy(抽象策略类):它为所支持的算法声明了抽象方法,是所有策略类的父类,它可以是抽象类或具体类,也可以是接口。环境类通过抽象策略类中声明的方法在运行时调用具体策略类中实现的算法。
ConcreteStrategy(具体策略类):它实现了在抽象策略类中声明的算法,在运行时,具体策略类将覆盖在环境类中定义的抽象策略类对象,使用一种具体的算法实现某个业务处理。
在策略模式中,对环境类和抽象策略类的理解非常重要,环境类是需要使用算法的类。在一个系统中可以存在多个环境类,它们可能需要重用一些相同的算法。

浙公网安备 33010602011771号