敏捷软件开发学习笔记(四)之结构型设计模式

PHP结构型设计模式

参考

  • 设计模式
  • PHP 设计模式全集 2018

什么是结构型是设计模式

结构型模式讲的是如何将类和对象按照某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,其中类结构型模式采用继承机制来组织接口和类,其中对象结构型模式采用组合和聚合来组合对象。由于组合和聚合比继承的耦合性低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

1.适配器设计模式(Adapter模式)

在现实生活中有很多类似的例子,如用直流电的笔记本电脑接交流电源时需要一个电源适配器,用计算机访问照相机的 SD 内存卡时需要一个读卡器等。

为什么需要适配器设计模式?

在软件设计中也可能出现:需要开发的具有某种业务功能的组件在现有的组件库中已经存在,但它们与当前系统的接口规范不兼容,如果重新开发这些组件成本又很高,这时用适配器模式能很好地解决这些问题。

什么是适配器设计模式?

适配器模式(Adapter)包含以下主要角色。

  • 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  • 适配者(Adaptee)类:它是被访问和适配的现存组件库中的组件接口。
  • 适配器(Adapter)类:它是一个转换器,通过继承或引用适配者的对象,把适配者接口转换成目标接口,让客户按目标接口的格式访问适配者。

即现在想要在 目标接口 中调用 适配者类 中的某些方法,所以定义一个 适配器类 继承 适配者类,实现目标接口

分类

适配器模式分为类结构型模式和对象结构型模式两种,前者类之间的耦合度比后者高,且要求程序员了解现有组件库中的相关组件的内部结构,所以应用相对较少些。

实例

实例一:使用类结构型模式

第一步:首先需要一个适配者类(已经存在的)
class Adaptee{public function usedMethod(){echo "this is Adaptee method";}
}
第二步:现在想要开发一个组件(源系统中存在,但是不符合规范)
interface Target{public function request();
}
第三步:定义一个适配器类
class Adapter extends Adaptee implements Target{public function request(){$this->usedMethod();}
}
第四步:使用
$adapter = new Adapter();
$adapter->request();

实例二:使用对象结构型模式

前两个条件与上面相同

第三步:定义一个适配器类
class Adapter implements Target{public $adaptee;public function __construct(Adaptee $adaptee){$this->adaptee = $adaptee;} public function request(){$this->adaptee->usedMethod();}
}
第四步:使用
$adapter = new Adapter();
$adapter->request(new Adaptee());

模式的应用场景

适配器模式(Adapter)通常适用于以下场景。

  • 以前开发的系统存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
  • 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。

2. 代理模式(Proxy)

在有些情况下,一个客户不能或者不想直接访问另一个对象,这时需要找一个中介帮忙完成某项任务,这个中介就是代理对象。例如,购买火车票不一定要去火车站买,可以通过 12306 网站或者去火车票代售点买。又如找女朋友、找保姆、找工作等都可以通过找中介完成。

为什么需要代理模式?

在软件设计中,如果由于某些原因(如安全)不想访问真实对象的话,可以使用代理模式。

什么是代理模式?

代理模式主要分为以下几个角色:

  • 抽象主题(Subject)类:通过接口或抽象类声明真实主题和代理对象实现的业务方法。
  • 真实主题(Real Subject)类:实现了抽象主题中的具体业务,是代理对象所代表的真实对象,是最终要引用的对象。
  • 代理(Proxy)类:提供了与真实主题相同的接口,其内部含有对真实主题的引用,它可以访问、控制或扩展真实主题的功能。

实例

第一步:首先存在一个抽象主题接口

Interface Subject{public function request();
}

第二步:存在一个真实主题

class RealSubject implements Subject{public function request(){echo "这个是真实主题\n";}
}

第三步:使用一个代理模式

class Proxy implements Subject{public $realSubject;public function __construct(){$this->realSubject = new RealSubject();    }public function request(){$this->preRequest();$this->realSubject->request();$this->postRequest();}public function preRequest(){echo "这是调用真实主题之前的\n";}public function postRequest(){echo "这是调用真实主题之后的\n";}
}

第四步:测试

$testProxy = new Proxy();
$testProxy->request();d

模式的应用场景

  • 远程代理,这种方式通常是为了隐藏目标对象存在于不同地址空间的事实,方便客户端访问。例如,用户申请某些网盘空间时,会在用户的文件系统中建立一个虚拟的硬盘,用户访问虚拟硬盘时实际访问的是网盘空间。
  • 虚拟代理,这种方式通常用于要创建的目标对象开销很大时。例如,下载一幅很大的图像需要很长时间,因某种计算比较复杂而短时间无法完成,这时可以先用小比例的虚拟代理替换真实的对象,消除用户对服务器慢的感觉。
  • 安全代理,这种方式通常用于控制不同种类客户对真实对象的访问权限。
  • 智能指引,主要用于调用目标对象时,代理附加一些额外的处理功能。例如,增加计算真实对象的引用次数的功能,这样当该对象没有被引用时,就可以自动释放它。
  • 延迟加载,指为了提高系统的性能,延迟对目标的加载。例如,Hibernate 中就存在属性的延迟加载和关联表的延时加载。

3. 桥梁模式(Bridge)

引用设计模式(八)桥梁模式(Bridge),这篇文章中的一个例子:

现需要提供大中小3种型号的画笔,能够绘制5种不同颜色,如果使用蜡笔,我们需要准备3*5=15支蜡笔,也就是说必须准备15个具体的蜡笔类。而如果使用毛笔的话,只需要3种型号的毛笔,外加5个颜料盒,用3+5=8个类就可以实现15支蜡笔的功能。实际上,蜡笔和毛笔的关键一个区别就在于笔和颜色是否能够分离

为什么需要Bridge模式?

一个类中有多个纬度的变化,那可以使用Bridge模式对该类进行解耦,即将多个纬度进行抽象。所以桥梁模式的用意是“将抽象化与实现化脱耦,使得二者可以独立地变化。”

什么是Bridge模式?

桥接(Bridge)模式包含以下主要角色。

  • 抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
  • 扩展抽象化(Refined Abstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
  • 实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
  • 具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。

实例

可以实现一个包含颜色的形状接口。

第一步:定义一个颜色接口(Implementor角色)。定义一个形状抽象类(Abstraction角色),其中包含一个颜色接口的引用。

//定义颜色接口
Interface Color{public function showColor();
}//形状抽象类
abstract class Shape
{protected $color;public function __construct(Color $color){$this->color = $color;}public function setColor(Color $color){$this->color = $color;}abstract public function draw();
}

第二步:实现具体化实现角色(Concrete Implementor)

class Red implements Color{public function showColor(){return "red";}
}class Green implements Color{public function showColor(){return "green";}
}

第三步:实现扩展抽象化(Refined Abstraction)角色

class Square extends Shape{public function draw(){echo "i am " . $this->color->showColor() . " square\n";}
}

第四步:测试

$redSquare = new Square(new Red());
$redSquare->draw();
$greenSquare = new Square(new Green());
$greenSquare->draw();

4.装饰模式(Decorator)

在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等。

为什么需要装饰模式?

在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰模式来实现。

什么是装饰模式?

装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

装饰模式主要包含以下角色。

  • 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  • 具体构件(Concrete Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  • 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  • 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

实例

比如现在有一个输出字符串接口,现在只能输出原有字符串,现在想要增加输出JSON,XML等字符串的功能。

第一步:先定义系统中已经存在的构件

Interface Component{public function renderData();
}class ConcreteComponent implements Component{public $data; public function __construct($data){$this->data = $data;}//输出字符串功能public function renderData(){return $this->data;      }
}

第二步:定义一个抽象装饰角色

abstract class Decorator implements Component
{protected $component;public function __construct(Component $component){$this->component = $component;}
}

第三步:定义具体的装饰类

// Json装饰类
class JsonComponent extends Decorator{public function renderData(){return json_encode($this->component->renderData());}
}// XML装饰类
class XmlComponent extends Decorator{public function renderData(){return "this is Xml renderData method";}
}

第四步:测试

$component = new ConcreteComponent(["1", "2"]);
var_dump($component->renderData());$jsonComponent = new JsonComponent($component);
var_dump($jsonComponent->renderData());$xmlComponent = new XmlComponent($component);
var_dump($xmlComponent->renderData());

转载于:https://www.cnblogs.com/qiye5757/p/10013048.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/412756.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

[css] position的relative和absolute定位原点是哪里?

[css] position的relative和absolute定位原点是哪里? absolute: 定位原点为第一个position不为static的父级元素的左上角。 可以基于该特性实现height:100%生效 relative:定位原点为元素本身的所在位置。 relative的偏移量设置会导致显示效果和定位原点…

javax.mail.MessagingException: while sending message;Connection reset by peer: socket write error

大家好,我是烤鸭: 阿里云邮件推送服务报错。当你也使用阿里云的邮件推送服务提示上面这个错误的话,我先告诉你原因和目前能想到的解决方案。 解决思路: 1. 换企业邮箱,阿里的上限15M,网易的不知道&…

李晓菁201771010114《面向对象程序设计(java)》第十三周学习总结

理论知识:事件处理 1.事件源:能够产生事件的对象都可以成为事件源,如文本框,按钮等。一个事件源是一个能够注册监听器并向监听器发送事件对象的对象。 2.事件监听器:事件监听器对象接收事件源发送的通告(事…

[css] 过渡和动画的区别是什么?

[css] 过渡和动画的区别是什么? 相同:都会让你的页面元素动起来 区别: 过渡 transition1.需要事件触发,比如hover,focus,checked , js改, media query 2.一次性的 3.只能定义开始和结束状态,不…

记一次 OOM 的原因和处理 出现大量 close_wait,项目无法访问 activeMq和 poi 出现的 OOM

大家好,我是烤鸭: 记一次项目无法访问的事件和处理。由于某个模块每隔几天就会出现无法访问,目前的最简单粗暴的方法就是重启。 1. 现象 项目内日志打印正常,经过dubbo的rpc服务和接口调用正常。http接口无法访问。提示nginx 502。 2.…

docker删除镜像和删除容器

删除容器:docker rm ID 删除镜像:docker rmi ID转载于:https://www.cnblogs.com/61355ing/p/10018498.html

[css] CSS中的calc()有什么作用?

[css] CSS中的calc()有什么作用? 用来计算长宽的属性,非常好用,百分比,px,vh/vm都可参与计算, 不过正如上面的大兄弟说的,运算符的左右要有空格,要不然不生效个人简介 我是歌谣,欢迎和大家一起交流前后端知识。放弃很容易, 但坚持一定很酷。…

fastjson导致的OOM

大家好,我是烤鸭: 今天又遇到OOM了,原因在于 fastjson 的 toJSONString。 这是线上的报错信息。 将这个 TotalLoanDTO 对象 toJSONString 导致的OOM。日志如下。 2019-10-31 12:07:49.896 [TID:285.93.15724948639339801] [XNIO-1 task-14] INFO [cla…

谷歌浏览器中安装JsonView扩展程序

实际开发工作中经常用到json数据,那么就会有这样一个需求:在谷歌浏览器中访问URL地址返回的json数据能否按照json格式展现出来。 比如,在谷歌浏览器中访问:http://jsonview.com/example.json 展现效果如下: 那么安装了…

[css] 怎么实现移动端的边框0.5px?

[css] 怎么实现移动端的边框0.5px&#xff1f; 一种是通过transform中的scaleborder: 1px solid red;transform: scaleY(.5);一种是通过meta viewport中设置init-scale为0.5 <meta name"viewport" content"widthdevice-width, initial-scale0.5"> 一…

Serialized class com.xxx.xxxService must implement java.io.Serializable

大家好&#xff0c;我是烤鸭&#xff1a; 使用dubbo的时候&#xff0c;遇到如下的问题。 Serialized class com.xxx.xxxService must implement java.io.Serializable 1. 异常 dubbo无论使用哪个协议传递参数的时候&#xff0c;都需要参数实现序列化接口。 所以提示这个…

CS229 7.1应用机器学习中的一些技巧

本文所讲述的是怎么样去在实践中更好的应用机器学习算法&#xff0c;比如如下经验风险最小化问题&#xff1a; 当求解最优的 后&#xff0c;发现他的预测误差非常之大&#xff0c;接下来如何处理来使得当前的误差尽可能的小呢&#xff1f;这里给出以下几个选项&#xff0c;下面…

[css] 行内元素和块级元素有什么区别,如何相互转换?

[css] 行内元素和块级元素有什么区别&#xff0c;如何相互转换&#xff1f; 一般通过display属性来区分块级元素和行内元素&#xff0c;block代表块级元素&#xff0c;inline代表行内元素。 块级元素&#xff1a; 1、内容独占一行。 2、width和height可以设置。 3、margin和pa…

dubbo源码解析(一)

大家好&#xff0c;我是烤鸭&#xff1a; 今天和大家分享dubbo的源码解析。 1.SPI http://dubbo.apache.org/zh-cn/docs/source_code_guide/dubbo-spi.html介绍: SPI 全称为 Service Provider Interface&#xff0c;是一种服务发现机制。 SPI 的本质是将接口实现类的全限定名配…

8号团队-团队任务三:每日立会(2018-11-27)

团队信息&#xff1a; 1.团队序号 8 2.开发软件 飞机大战 3.今日整理人&#xff1a;徐浩茗 职位&#xff1a;项目经理 学号&#xff1a;2016035107247 4.本次团队会议共有8人参加 无缺席 团队汇报&#xff1a; &#xff08;截图&#xff09;如下 . 4.燃尽图 5.本次会议中遇…

[css] 说说你对低版本IE的盒子模型的理解

[css] 说说你对低版本IE的盒子模型的理解 一个CSS盒子由四部分组成&#xff0c;由内到外依次是&#xff1a;content、padding、border、margin。所谓盒子模型定义的是盒子宽高的计算方法&#xff0c;IE盒子模型的宽高为content、padding、border之和。而W3C盒子的宽高仅为cont…

Alibaba 开源工具 Arthas 使用

大家好&#xff0c;我是烤鸭&#xff1a; 很长时间没更新了&#xff0c;最近太忙了&#xff0c;只能抽空水点文章了&#xff0c;今天给大家介绍的是阿里的开源工具 Arthas 的使用。 1. 开源地址 Arthas 是Alibaba开源的Java诊断工具 https://github.com/alibaba/arthas 中文说…

[css] 你是如何规划响应式布局的?

[css] 你是如何规划响应式布局的&#xff1f; 从项目角度来讲&#xff0c; PC 和 Mobile 是一个项目还是两个项目&#xff1b;从方法流派来讲&#xff0c; 有栅栏布局&#xff0c;固定 viewport&#xff0c;使用 rem/pt/vw 单位&#xff0c;使用定位百分比&#xff0c;修改为 …

Oracle 用户,角色,权限等

权限管理是 Oracle 系统的精华&#xff0c;不同用户登录到同一数据库中&#xff0c;可能看到不同数量的表&#xff0c;拥有不同的权限。Oracle 的权限分为系统权限和数据对象权限&#xff0c;共一百多种&#xff0c;如果单独对用户授权&#xff0c;很囧&#xff0c;有一些用户需…

Java 面试题(4)—— 多线程

Java实现多线程有哪几种方式。 implements Runnable, implements Callable,extends Thread Callable和Future、FutureTask的了解。 Callable和 Future 是juc包下的接口。 Callable 可以异步执行任务&#xff0c;一般和 ExecutorService 的submit方法一起使用。 Future 可以监听…