设计模式(三),结构型模式

简介: 设计模式(三),结构型模式
  • 外观模式
    外观模式 (Facade Pattern):外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。外观模式又称为门面模式,它是一种对象结构型模式。
    举一个简单的例子,相信大家都使用过 C++ 语言,他是一门编译型语言,写完代码之后,我们需要经过编译之后才能运行,在 IDE 中,会有一个 Build 的按钮,点击它即可完成编译过程,但是这一个简单的动作背后,却是一系列复杂操作的协调配合,至少包括词法分析,语法分析,生成中间代码,生成汇编代码以及链接等操作,作为普通开发人员,我们不必在意这些过程是如何完成的,只需要点击 Build 按钮,IDE 就会自动帮我们完成背后的工作。那么这个 Build 按钮就是 IDE 为我们提供的高级接口,通过他来完成各种子系统的协调工作。
    角色:
    Facade:外观角色,提供高级接口
    SubSystem:子系统角色,负责各自的功能实现
    UML 类图
    示例代码
<?php 
class SystemA
{
  public function operationA()
  {
      echo "operationA <br>";
  }
}
class SystemB
{
  public function operationB()
  {
      echo "operationB <br>";
  }
}
class SystemC
{
  public function operationC()
  {
      echo "operationC <br>";
  }
}
class Facade
{
  protected $systemA;
  protected $systemB;
  protected $systemC;
  function __construct()
  {
      $this->systemA = new SystemA();
      $this->systemB = new SystemB();
      $this->systemC = new SystemC();
  }
  public function myOperation()
  {
      $this->systemA->operationA();
      $this->systemB->operationB();
      $this->systemC->operationC();
  }
}
$facade = new Facade();
$facade->myOperation();
  • 使用外观模式最大的优点就是子系统与客户端之间是松耦合的关系,客户端不必知道具体有哪些子系统,也无需知道他们是如何工作的,通过引入一个外观类,提供一个客户端间接访问子系统的高级接口。子系统和外观类可以独立运作,修改某一个子系统的内容,不会影响到其他子系统,也不会影响到外观对象。不过它的缺点就是它不够灵活,当需要增加一个子系统的时候,需要修改外观类。
  • 享元模式
    享元模式(英语:Flyweight Pattern)是一种软件设计模式)。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。由于享元模式要求能够共享的对象必须是细粒度对象,因此它又称为轻量级模式,它是一种对象结构型模式。
    要理解享元模式,先要理解两个重要的概念:内部状态和外部状态。
    内部状态存储于 flyweight 中,它包含了独立于 flyweight 场景的信息,这些信息使得 flyweight 可以被共享。而外部状态取决于 flyweight 场景,并根据场景而变化,因此不可共享。用户对象负责在必要的时候将外部状态传递给 flyweight。
    角色
    Flyweight: 抽象享元类
    ConcreteFlyweight: 具体享元类
    UnsharedConcreteFlyweight: 非共享具体享元类
    FlyweightFactory: 享元工厂类
    UML类图
    示例代码
<?php
interface Flyweight{
  public function operation();
}
class MyFlyweight implements Flyweight
{
  protected $intrinsicState;
  function __construct($str)
  {
      $this->intrinsicState = $str;
  }
  public function operation()
  {
      echo 'MyFlyweight['.$this->intrinsicState.'] do operation. <br>';
  }
}
class FlyweightFactory
{
  protected static $flyweightPool;
  function __construct()
  {
      if (!isset(self::$flyweightPool)) {
          self::$flyweightPool = [];
      }
  }
  public function getFlyweight($str)
  {
      if (!array_key_exists($str,self::$flyweightPool)) {
          $fw = new MyFlyweight($str);
          self::$flyweightPool[$str] = $fw;
          return $fw;
      } else {
          echo "aready in the pool,use the exist one: <br>";
          return self::$flyweightPool[$str];
      }
  }
}
$factory = new FlyweightFactory();
$fw = $factory->getFlyweight('one');
$fw->operation();
$fw1 = $factory->getFlyweight('two');
$fw1->operation();
$fw2 = $factory->getFlyweight('one');
$fw2->operation();
  • 享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。
  • 代理模式
    所谓的代理者是指一个类别可以作为其它东西的接口。代理者可以作任何东西的接口:网络连接、内存中的大对象、文件或其它昂贵或无法复制的资源。
    代理对象可以在客户端和目标对象之间起到 中介的作用,并且可以通过代理对象去掉客户不能看到 的内容和服务或者添加客户需要的额外服务。
    可能大家听得最多且最常用的就是 VPN 网络代理,或者代理服务器等。
    角色
    Subject: 抽象主题角色
    Proxy: 代理主题角色
    RealSubject: 真实主题角色
    UML类图
    示例代码
<?php 
interface Subject{
  public function request();
}
class RealSubject implements Subject
{
  public function request()
  {
      echo "RealSubject::request <br>";
  }
}
class Proxy implements Subject
{
  protected $realSubject;
  function __construct()
  {
      $this->realSubject = new RealSubject();
  }
  public function beforeRequest()
  {
      echo "Proxy::beforeRequest <br>";
  }
  public function request()
  {
      $this->beforeRequest();
      $this->realSubject->request();
      $this->afterRequest();
  }
  public function afterRequest()
  {
      echo "Proxy::afterRequest <br>";
  }
}
$proxy = new Proxy();
$proxy->request();

下面将会介绍五种行为型模式。

  • 命令模式
    在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。
    主要特点就是将一个请求封装为一个对象,从而使我们可用不同的请求对客户进行参数化;对请求排队或者记录请求日志,以及支持可撤销的操作。命令模式是一种对象行为型模式,其别名为动作 (Action) 模式或事务 (Transaction) 模式。
    角色
    Command: 抽象命令类
    ConcreteCommand: 具体命令类
    Invoker: 调用者
    Receiver: 接收者
    Client: 客户类
    UML类图
    示例代码
<?php 
class Receiver
{
  public function Action()
  {
      echo "Receiver->Action";
  }
}
abstract class Command{
  protected $receiver;
  function __construct(Receiver $receiver)
  {
      $this->receiver = $receiver;
  }
  abstract public function Execute();
}
class MyCommand extends Command
{
  function __construct(Receiver $receiver)
  {
      parent::__construct($receiver);
  }
  public function Execute()
  {
      $this->receiver->Action();
  }
}
class Invoker
{
  protected $command;
  function __construct(Command $command)
  {
      $this->command = $command;
  }
  public function Invoke()
  {
      $this->command->Execute();
  }
}
$receiver = new Receiver();
$command = new MyCommand($receiver);
$invoker = new Invoker($command);
$invoker->Invoke();
  • 中介者模式
    《设计模式:可复用面向对象软件的基础》一书中对中介者模式定义:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
    举个简单的例子,就比如大家平时喜欢用微信聊天,你发送的聊天内容需要通过微信服务器进行中间处理,然后下发给你的好友,微信服务器就是一个中介者。
    角色
    Mediator: 抽象中介者
    ConcreteMediator: 具体中介者
    Colleague: 抽象同事类
    ConcreteColleague: 具体同事类
    UML类图
    示例代码
<?php 
abstract class Colleague{
  protected $mediator;
  abstract public function sendMsg($who,$msg);
  abstract public function receiveMsg($msg);
  public function setMediator(Mediator $mediator){
      $this->mediator = $mediator;
  }
}
class ColleagueA extends Colleague
{
  public function sendMsg($toWho,$msg)
  {
      echo "Send Msg From ColleagueA To: ".$toWho . '<br>';
      $this->mediator->opreation($toWho,$msg);
  }
  public function receiveMsg($msg)
  {
      echo "ColleagueA Receive Msg: ".$msg . '<br>';
  }
}
class ColleagueB extends Colleague
{
  public function sendMsg($toWho,$msg)
  {
      echo "Send Msg From ColleagueB To: ".$toWho . '<br>';
      $this->mediator->opreation($toWho,$msg);
  }
  public function receiveMsg($msg)
  {
      echo "ColleagueB Receive Msg: ".$msg . '<br>';
  }
}
abstract class Mediator{
  abstract public function opreation($id,$message);
  abstract public function register($id,Colleague $colleague);
}
class MyMediator extends Mediator
{
  protected static $colleagues;
  function __construct()
  {
      if (!isset(self::$colleagues)) {
          self::$colleagues = [];
      }
  }
  public function opreation($id,$message)
  {
      if (!array_key_exists($id,self::$colleagues)) {
          echo "colleague not found";
          return;
      }
      $colleague = self::$colleagues[$id];
      $colleague->receiveMsg($message);
  }
  public function register($id,Colleague $colleague)
  {
      if (!in_array($colleague, self::$colleagues)) {
          self::$colleagues[$id] = $colleague;
      }
      $colleague->setMediator($this);
  }
}
$colleagueA = new ColleagueA();
$colleagueB = new ColleagueB();
$mediator = new MyMediator();
$mediator->register(1,$colleagueA);
$mediator->register(2,$colleagueB);
$colleagueA->sendMsg(2,'hello admin');
$colleagueB->sendMsg(1,'shiyanlou');
  • 中介者模式的两个主要作用:中转作用(结构性):通过中介者提供的中转作用,各个同事对象就不再需要显式引用其他同事,当需要和其他同事进行通信时,通过中介者即可。该中转作用属于中介者在结构上的支持。
    协调作用(行为性):中介者可以更进一步的对同事之间的关系进行封装,同事可以一致地和中介者进行交互,而不需要指明中介者需要具体怎么做,中介者根据封装在自身内部的协调逻辑,对同事的请求进行进一步处理,将同事成员之间的关系行为进行分离和封装。该协调作用属于中介者在行为上的支持。
  • 观察者模式在此种模式中,一个目标对象管理所有相依于它的观察者对象,并且在它本身的状态改变时主动发出通知。这通常透过呼叫各观察者所提供的方法来实现。此种模式通常被用来实时事件处理系统。观察者模式又叫做发布 - 订阅(Publish/Subscribe)模式、模型 - 视图(Model/View)模式、源 - 监听器(Source/Listener)模式或从属者(Dependents)模式。角色Subject: 抽象目标类,一般至少提供三个接口:
  • 添附 (Attach):新增观察者到串炼内,以追踪目标对象的变化。
  • 解附 (Detach):将已经存在的观察者从串炼中移除。
  • 通知 (Notify):利用观察者所提供的更新函式来通知此目标已经产生变化。
  • ConcreteSubject: 具体目标,提供了观察者欲追踪的状态,也可设置目标状态
    Observer: 抽象观察者,定义观察者的更新操作接口
    ConcreteObserver: 具体观察者,实现抽象观察者的接口,做出自己的更新操作
    UML类图
    示例代码
<?php 
abstract class Obeserver{
  abstract function update(Subject $sub);
}
abstract class Subject{
  protected static $obeservers;
  function __construct()
  {
      if (!isset(self::$obeservers)) {
          self::$obeservers = [];
      }
  }
  public function attach(Obeserver $obeserver){
      if (!in_array($obeserver, self::$obeservers)) {
          self::$obeservers[] = $obeserver;
      }
  }
  public function deattach(Obeserver $obeserver){
      if (in_array($obeserver, self::$obeservers)) {
          $key = array_search($obeserver,self::$obeservers);
          unset(self::$obeservers[$key]);
      }
  }
  abstract public function setState($state);
  abstract public function getState();
  public function notify()
  {
      foreach (self::$obeservers as $key => $value) {
          $value->update($this);
      }
  }
}
class MySubject extends Subject
{
  protected $state;
  public function setState($state)
  {
      $this->state = $state;
  }
  public function getState()
  {
      return $this->state;
  }
}
class MyObeserver extends Obeserver
{
  protected $obeserverName;
  function __construct($name)
  {
      $this->obeserverName = $name;
  }
  public function update(Subject $sub)
  {
      $state = $sub->getState();
      echo "Update Obeserver[".$this->obeserverName.'] State: '.$state . '<br>';
  }
}
$subject = new MySubject();
$one = new MyObeserver('one');
$two = new MyObeserver('two');
$subject->attach($one);
$subject->attach($two);
$subject->setState(1);
$subject->notify();
echo "--------------------- <br>";
$subject->setState(2);
$subject->deattach($two);
$subject->notify();
  • 主要作用:
  • 当抽象个体有两个互相依赖的层面时。封装这些层面在单独的对象内将可允许程序员单独地去变更与重复使用这些对象,而不会产生两者之间交互的问题。
  • 当其中一个对象的变更会影响其他对象,却又不知道多少对象必须被同时变更时。
  • 当对象应该有能力通知其他对象,又不应该知道其他对象的实做细节时。
  • 状态模式
    状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。其别名为状态对象 (Objects for States),状态模式是一种对象行为型模式。
    有时,一个对象的行为受其一个或多个具体的属性变化而变化,这样的属性也叫作状态,这样的的对象也叫作有状态的对象。
    角色
    Context: 环境类,维护一个 ConcreteState 子类的实例,这个实例定义当前状态;
    State: 抽象状态类,定义一个接口以封装与 Context 的一个特定状态相关的行为;
    ConcreteState: 具体状态类,每一个子类实现一个与 Context 的一个状态相关的行为。
    UML类图
    示例代码
<?php 
class Context{
  protected $state;
  function __construct()
  {
      $this->state = StateA::getInstance();
  }
  public function changeState(State $state)
  {
      $this->state = $state;
  }
  public function request()
  {
      $this->state->handle($this);
  }
}
abstract class State{
  abstract function handle(Context $context);
}
class StateA extends State
{
  private static $instance;
  private function __construct(){}
  private function __clone(){}
  public static function getInstance()
  {
      if (!isset(self::$instance)) {
          self::$instance = new self;
      }
      return self::$instance;
  }
  public function handle(Context $context)
  {
      echo "doing something in State A.\n done,change state to B <br>";
      $context->changeState(StateB::getInstance());
  }
}
class StateB extends State
{
  private static $instance;
  private function __construct(){}
  private function __clone(){}
  public static function getInstance()
  {
      if (!isset(self::$instance)) {
          self::$instance = new self;
      }
      return self::$instance;
  }
  public function handle(Context $context)
  {
      echo "doing something in State B.\n done,change state to A <br>";
      $context->changeState(StateA::getInstance());
  }
}
$context = new Context();
$context->request();
$context->request();
$context->request();
$context->request();
  • 策略模式
    策略模式 (Strategy Pattern):定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法独立于使用它的客户而变化,也称为政策模式 (Policy)。
    常见示例:常见的排序算法有快速排序,冒泡排序,归并排序,选择排序等,如果我们需要在一个算法类中提供这些算法,一个常见的解决方法就是在类中定义多个方法,每个方法定义一种具体的排序算法,然后使用 if...else... 去判断到底是哪种算法,或者直接调用某个具体方法。这种方法是将算法的实现硬编码到类中,这样做最大的弊端就是算法类类非常臃肿,而且当需要增加或者更换一种新的排序方法时候,需要修改算法类的代码,同时也需要修改客户端调用处的代码。策略模式就是为了解决这列问题而设计的。
    角色
    Context: 环境类,使用一个 ConcreteStrategy 对象来配置;维护一个对 Stategy 对象的引用,同时,可以定义一个接口来让 Stategy 访问它的数据。
    Strategy: 抽象策略类,定义所有支持的算法的公共接口。Context 使用这个接口来调用某 ConcreteStrategy 定义的算法;
    ConcreteStrategy: 具体策略类,实现 Strategy 接口的具体算法;
    UML类图
    示例代码
<?php 
abstract class Strategy{
  abstract function use();
}
class StrategyA extends Strategy
{
  public function use()
  {
      echo "这是使用策略A的方法 <br>";
  }
}
class StrategyB extends Strategy
{
  public function use()
  {
      echo "这是使用策略B的方法 <br>";
  }
}
class Context
{
  protected $startegy;
  public function setStrategy(Strategy $startegy)
  {
      $this->startegy = $startegy;
  }
  public function use()
  {
      $this->startegy->use();
  }
}
$context = new Context();
$startegyA = new StrategyA();
$startegyB = new StrategyB();
$context->setStrategy($startegyA);
$context->use();
$context->setStrategy($startegyB);
$context->use();
相关文章
|
3月前
|
设计模式 存储 Java
【十】设计模式~~~结构型模式~~~享元模式(Java)
文章详细介绍了享元模式(Flyweight Pattern),这是一种对象结构型模式,通过共享技术实现大量细粒度对象的重用,区分内部状态和外部状态来减少内存中对象的数量,提高系统性能。通过围棋棋子的设计案例,展示了享元模式的动机、定义、结构、优点、缺点以及适用场景,并探讨了单纯享元模式和复合享元模式以及与其他模式的联用。
【十】设计模式~~~结构型模式~~~享元模式(Java)
|
3月前
|
设计模式 存储 Java
【九】设计模式~~~结构型模式~~~外观模式(Java)
文章详细介绍了外观模式(Facade Pattern),这是一种对象结构型模式,通过引入一个外观类来简化客户端与多个子系统之间的交互,降低系统的耦合度,并提供一个统一的高层接口来使用子系统。通过文件加密模块的实例,展示了外观模式的动机、定义、结构、优点、缺点以及适用场景,并讨论了如何通过引入抽象外观类来提高系统的可扩展性。
【九】设计模式~~~结构型模式~~~外观模式(Java)
|
3月前
|
设计模式 Java
【八】设计模式~~~结构型模式~~~装饰模式(Java)
文章详细介绍了装饰模式(Decorator Pattern),这是一种对象结构型模式,用于在不使用继承的情况下动态地给对象添加额外的职责。装饰模式通过关联机制,使用装饰器类来包装原有对象,并在运行时通过组合的方式扩展对象的行为。文章通过图形界面构件库的设计案例,展示了装饰模式的动机、定义、结构、优点、缺点以及适用场景,并提供了Java代码实现和应用示例。装饰模式提高了系统的灵活性和可扩展性,适用于需要动态、透明地扩展对象功能的情况。
【八】设计模式~~~结构型模式~~~装饰模式(Java)
|
3月前
|
设计模式 XML 存储
【七】设计模式~~~结构型模式~~~桥接模式(Java)
文章详细介绍了桥接模式(Bridge Pattern),这是一种对象结构型模式,用于将抽象部分与实现部分分离,使它们可以独立地变化。通过实际的软件开发案例,如跨平台视频播放器的设计,文章阐述了桥接模式的动机、定义、结构、优点、缺点以及适用场景,并提供了完整的代码实现和测试结果。桥接模式适用于存在两个独立变化维度的系统,可以提高系统的可扩展性和灵活性。
【七】设计模式~~~结构型模式~~~桥接模式(Java)
|
6月前
|
设计模式 存储 安全
Java设计模式---结构型模式
Java设计模式---结构型模式
|
3月前
|
设计模式 XML 存储
【六】设计模式~~~结构型模式~~~适配器模式(Java)
文章详细介绍了适配器模式(Adapter Pattern),这是一种结构型设计模式,用于将一个类的接口转换成客户期望的另一个接口,使原本不兼容的接口能够一起工作,提高了类的复用性和系统的灵活性。通过对象适配器和类适配器两种实现方式,展示了适配器模式的代码应用,并讨论了其优点、缺点以及适用场景。
|
3月前
|
设计模式 缓存 Java
【十一】设计模式~~~结构型模式~~~代理模式(Java)
文章详细介绍了代理模式(Proxy Pattern),这是一种对象结构型模式,用于给对象提供一个代理以控制对它的访问。文中阐述了代理模式的动机、定义、结构、优点、缺点和适用环境,并探讨了远程代理、虚拟代理、保护代理等不同代理形式。通过一个商务信息查询系统的实例,展示了如何使用代理模式来增加身份验证和日志记录功能,同时保持客户端代码的无差别对待。此外,还讨论了代理模式在分布式技术和Spring AOP中的应用,以及动态代理的概念。
【十一】设计模式~~~结构型模式~~~代理模式(Java)
|
6月前
|
设计模式 Java 应用服务中间件
设计模式 -结构型模式_门面模式(外观模式) Facade Pattern 在开源软件中的应用
设计模式 -结构型模式_门面模式(外观模式) Facade Pattern 在开源软件中的应用
61 1
|
5月前
|
设计模式
设计模式之结构型模式
设计模式之结构型模式
|
6月前
|
设计模式 缓存 监控
JAVA设计模式之结构型模式
结构模型:适配器模型、桥接模型、过滤器模型、组合模型、装饰器模型、外观模型、享受元模型和代理模型。
68 3