php设计模式(二):结构模式
上一篇我们介绍了设计模式的特性并且详细讲解了4种创建型模式,创建型模式是负责如何产生对象实例的,现在我们继续来给大家介绍结构型模式。
一、什么是结构型模式?
结构型模式是解析类和对象的内部结构和外部组合,通过优化程序结构解决模块之间的耦合问题。
二、结构型模式的种类:
适配器模式
桥接模式
装饰模式
组合模式
外观模式
享元模式
代理模式
1、 适配器模式(Adapter)
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本的由于接口不兼容而不能一起工作的那些类可以一起工作。
应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
代码实现
<?php
/**
* 优才网公开课示例代码
*
* 适配器模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/ //老的代码
class User {
private $name;
function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
} //新代码,开放平台标准接口
interface UserInterface {
function getUserName();
}
class UserInfo implements UserInterface {
protected $user;
function __construct($user) {
$this->user = $user;
}
public function getUserName() {
return $this->user->getName();
}
} $olduser = new User('张三');
echo $olduser->getName()."n";
$newuser = new UserInfo($olduser);
echo $newuser->getUserName()."n"; ?>
注意点:这里的新接口使用了组合方式,UserInfo内部有一个成员变量保存老接口User对象,模块之间是松耦合的,这种结构其实就是组合模式。不要使用继承,虽然UserInfo继承User也能达到同样的目的,但是耦合度高,相互产生影响。
2、 桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立变化
特点:独立存在,扩展性强
应用:需要不断更换调用对象却执行相同的调用方法,实现扩展功能
代码实现
<?php
/**
* 优才网公开课示例代码
*
* 桥接模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/ abstract class Person {
abstract function getJob();
} class Student extends Person {
public function getJob() {
return '学生';
}
} class Teacher extends Person {
public function getJob() {
return '老师';
}
} class BridgeObj {
protected $_person; public function setPerson($person) {
$this->_person = $person;
} public function getJob() {
return $this->_person->getJob();
}
} $obj = new BridgeObj();
$obj->setPerson(new Student());
printf("本次桥接对象:%sn", $obj->getJob());
$obj->setPerson(new Teacher());
printf("本次桥接对象:%sn", $obj->getJob()); ?>
3、 装饰模式
动态地给一个对象添加额外的职责。在原有的基础上进行功能增强。
特点:用来增强原有对象功能,依附于原有对象。
应用:用于需要对原有对象增加功能而不是完全覆盖的时候
代码实现
<?php
/**
* 优才网公开课示例代码
*
* 装饰模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/ //产品
abstract class Person {
abstract function getPermission();
}
//被装饰者
class User extends Person {
public function getPermission() {
return '公开文档';
}
}
//装饰类
class PermUser extends Person {
protected $_user;
protected $_special = '';
function __construct($user) {
$this->_user = $user;
}
public function getPermission() {
return $this->_user->getPermission() . $this->_special;
}
}
//装饰类产品
class JavaUser extends PermUser {
protected $_special = ' java程序';
}
class CPlusUser extends PermUser {
protected $_special = ' c++程序';
} $user = new User();
printf("permission:%sn", $user->getPermission());
$user = new JavaUser($user);
printf("permission:%sn", $user->getPermission());
$user = new CPlusUser($user);
printf("permission:%sn", $user->getPermission()); ?>
大家想想装饰和继承的区别在哪?
如果是上面的例子,如果用继承,是CPlusUser继承JavaUser还是反过来呢?谁也不知道最终使用者需要哪一种。
在多层关系的情况下,装饰是和顺序无关并且随时增加装饰,而继承只能是特定的顺序,所以装饰模式会更加的灵活。
4、组合模式
将对象组合成树形结构表示“部分-整体”的层次结构。
特点:灵活性强
应用:对象的部分-整体的层次结构,模糊组合对象和简单对象处理问题
代码实现
<?php
/**
* 优才网公开课示例代码
*
* 组合模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/ //继承模式 class UserBaseInfo {
private $name; function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
}
class User extends UserBaseInfo {
private $login = false; public function setLogin($islogin) {
$this->login = $islogin;
}
public function isLogin() {
return $this->login;
}
} $user = new User('张三');
$user->setLogin(true);
if ($user->isLogin()) {
echo $user->getName()."已经登录了n";
} else {
echo $user->getName()."还没有登录n";
} //组合模式 class LoginInfo {
protected $user;
protected $login = false; public function setLogin($user, $isLogin) {
$this->user = $user;
$this->login = $isLogin;
}
public function isLogin() {
return $this->login;
}
} $user = new User('张三');
$login = new LoginInfo();
$login->setLogin($user, true);
if ($login->isLogin()) {
echo $user->getName()."已经登录了n";
} else {
echo $user->getName()."还没有登录n";
} //部分可以更换,用继承则不行
class Admin {
protected $level;
function __construct($level) {
$this->level = $level;
}
function getLevel() {
return $this->level;
}
}
$admin = new Admin(1);
$login->setLogin($admin, true);
if ($login->isLogin()) {
printf("级别为 %d 的管理员已经登录了n", $admin->getLevel());
} else {
printf("级别为 %d 的管理员还没有登录n", $admin->getLevel());
} ?>
上面的例子分别展示了使用继承和组合来处理新功能,在简单的情况下看似区别不大,但在项目后期越来越复杂的时候组合模式的优势就越来越明显了。
例如上面的登录信息,如果要增加登录次数、最后登录时间、登录ip等信息,登录本身就会变成一个比较复杂的对象。如果以后有新的需求比如好友信息、用户的访问信息等,再要继承的话,用户类就会变得非常庞大,难免各父类之间没有冲突的变量和方法,而外部访问用户类的众多方法也变得很费劲。采用组合模式后,一个类负责一个角色,功能区分非常明显,扩展方便。
5、 外观模式(门面模式)
为了系统中的一组接口提供一个一致的界面
特点:向上抽取,有共性
应用:内部接口众多,由统一的接口来调用
代码实现
<?php
/**
* 优才网公开课示例代码
*
* 外观模式,也叫门面模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/ class Operation {
public function testPlus() {
printf("plus: %sn", (1 + 2 == 3 ? 'true' : 'false'));
}
public function testMinus() {
printf("minus: %sn", (3 - 2 == 2 ? 'true' : 'false'));
}
public function testTimes() {
printf("times: %sn", (2 * 3 == 6 ? 'true' : 'false'));
}
} class Tester {
protected $_operation;
function __construct() {
$this->_operation = new Operation();
}
public function testAll() {
$this->_operation->testPlus();
$this->_operation->testMinus();
$this->_operation->testTimes();
}
} //测试用例,测试全部接口
$tester = new Tester();
$tester->testAll(); ?>
门面模式估计大家在实际代码中都已经使用到了,接口较多时把相似功能的接口封装成一个接口供外部调用,这就是门面模式。
6、 享元模式
运用共享技术有效地支持大量细粒度对象,采用一个共享来避免大量有相同内容对象的开销。这种开销中最直观的就是内存的损耗。
特点:高效性,共享性
应用:系统底层的设计。例如字符串的创建。如果两个字符串相同,则不会创建第二个字符串,而是第二个的引用直接指向第一个字符串。$str1=”abc”,$str2=”abc”.则内存存储中只会创建一个字符串“abc”而引用$str1.$str2都会指向它。
7、 代理模式
为其他对象提供一个代理来控制对这个对象的访问,就是给某一对象提供代理对象,并由代理对象控制具体对象的引用。能够协调调用者和被调用者,能够在一定程度上降低系统的耦合性。
特点:低耦合性,独立性好,安全性
应用:客户访问不到或者被访问者希望隐藏自己,所以通过代理来访问自己。
代码实现
<?php
/**
* 优才网公开课示例代码
*
* 代理模式
*
* @author 优才网全栈工程师教研组
* @see http://www.ucai.cn
*/ //内部对象
class User {
public function getName() {
return '张三';
}
public function getType() {
return '付费用户';
}
} //代理接口定义,例如开放平台
interface UserInterface {
function getName();
}
//代理对象
class UserProxy implements UserInterface {
protected $_user;
function __construct() {
$this->_user = new User();
}
public function getName() {
return $this->_user->getName();
}
} //内部调用
$user = new User();
printf("user name:%sn", $user->getName());
printf("user type:%sn", $user->getType());
//外部调用
// $user = new UserProxy();
// printf("user name:%sn", $user->getName());
// printf("user type:%sn", $user->getType()); //不能访问,及时知道内部对象有这个方法 ?>
三、总结
1、代理模式、适配器模式、门面模式、装饰模式的区别
a、 相同之处:都封装一个内部对象,调用内部对象的方法
b、 不同之处:各自有各自的特性和应用场景,不能相互替代。所以用的时候要仔细分析用那种合适。
2、 关于模式的选用问题
模式的选用要根据实际的业务需求,通过对业务逻辑的仔细分析,再根据模式具有的特性和应用场景进行合理的选择和区分。大部分情况下业务的场景决定了哪种模式,而不是选择哪个模式去实现一个业务,少数情况几种模式确实都能解决问题,那主要就是考虑以后的扩展了。
到这里我们已经了解了7种结构型模式,下一篇我们继续给大家介绍设计模式的行为型模式,先预览一下行为型模式的种类吧:
模版方法模式
命令模式
迭代器模式
观察者模式
终结者模式
备忘录模式
解释器模式
状态模式
策略模式
职责链模式
访问者模式
视频地址:http://www.ucai.cn/opencourse/98?f=10
php设计模式(二):结构模式的更多相关文章
- Java设计模式之结构模式
一.外观模式 分析:外观模式是为子系统的一组接口提供一个统一的界面,数据库JDBC连接应用就是外观模式的一个典型例子,特点:降低系统的复杂度,增加灵活性.结果:代码示例: public class D ...
- 设计模式 ( 二十 ) 访问者模式Visitor(对象行为型)
设计模式 ( 二十 ) 访问者模式Visitor(对象行为型) 1.概述 在软件开发过程中,对于系统中的某些对象,它们存储在同一个集合collection中,且具有不同的类型,而且对于该集合中的对象, ...
- C#设计模式之二十二访问者模式(Visitor Pattern)【行为型】
一.引言 今天我们开始讲"行为型"设计模式的第九个模式,该模式是[访问者模式],英文名称是:Visitor Pattern.如果按老规矩,先从名称上来看看这个模式,我根本不能获 ...
- 设计模式之代理模式之二(Proxy)
from://http://www.cnblogs.com/xwdreamer/archive/2012/05/23/2515306.html 设计模式之代理模式之二(Proxy) 0.前言 在前 ...
- Java 设计模式之工厂模式(二)
原文地址:Java 设计模式之工厂模式(二) 博客地址:http://www.extlight.com 一.背景 本篇内容是 Java 设计模式创建型模式的第二篇.上一篇主题为 <Java 设计 ...
- [JAVA设计模式]第三部分:结构模式
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 十二、结构模式之门面(Facade)模式
什么是门面模式 门面模式(也有翻译为外观模式)是对象的结构模式,外部与一个子系统的通信必须通过一个统一的门面进行.其为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子 ...
- 浅析JAVA设计模式之工厂模式(二)
1 工厂方法模式简单介绍 工厂方法 (Factroy Method)模式:又称多态性工厂模式(Polymorphic Factory),在这样的模式中,核心工厂不再是一个详细的类.而是一个抽象工厂,提 ...
- [工作中的设计模式]享元模式模式FlyWeight
一.模式解析 Flyweight在拳击比赛中指最轻量级,即“蝇量级”或“雨量级”,这里选择使用“享元模式”的意译,是因为这样更能反映模式的用意.享元模式是对象的结构模式.享元模式以共享的方式高效地支持 ...
- C#设计模式(13)——代理模式(Proxy Pattern)
一.引言 在软件开发过程中,有些对象有时候会由于网络或其他的障碍,以至于不能够或者不能直接访问到这些对象,如果直接访问对象给系统带来不必要的复杂性,这时候可以在客户端和目标对象之间增加一层中间层,让代 ...
随机推荐
- spring常规任务(轻便易)
spring提供了定时任务功能.我们不需要第三者jar包支持.spring够了. 代码: package com.inth.product.web.task; import java.util.Dat ...
- 玩转Web之JavaScript(四)-----javaScript语法总结(四) JS中的函数
1.function/return function用来定义函数(位于head部分),函数包含着一些代码,这些代码只能被事件激活,或者在函数被调用时才会执行. return 用来从函数中返回值 ...
- 复制(1)——SQLServer 复制简介
原文:复制(1)--SQLServer 复制简介 前言: SQLServer的复制技术最少从SQLServer2000时代已经出现,当初是为了分布式计算,不是为了高可用.但是到了今天,复制也成为了一种 ...
- SDL2来源分析3:渲染(SDL_Renderer)
===================================================== SDL源代码分析系列文章上市: SDL2源码分析1:初始化(SDL_Init()) SDL2 ...
- RH253读书笔记(1)-Lab 1 System Monitoring
Lab 1 System Monitoring Goal: To build skills to better assess system resources, performance and sec ...
- Android使用HttpURLConnection下载图片
讲到http就必须要了解URI和URL URI (uniform resource identifier)统一资源标志符: URL(uniform resource location )统一资源定位符 ...
- SQL Server 2005中的CHECKSUM功能
原文:SQL Server 2005中的CHECKSUM功能 转自此处 页面 checksum 是SQL2005的新功能,提供了一种比残缺页检测强大的机制检测IO方面的损坏.以下是详细描述: 页面 C ...
- HDU 3313 Key Vertex(dfs + bfs)
HDU 3313 Key Vertex 题目链接 题意:一个有向无环图.求s,t之间的割点 思路:先spfa找一条最短路出来,假设不存在.就n个都是割点. 然后每次从s进行dfs,找到能经过最短路上的 ...
- Javascript入门视频教程
1,第一节 http://pan.baidu.com/play/video#video/path=%2F%E6%95%99%E5%AD%A61.mov&t=-1 2,第二节 http://pa ...
- java_访问权限修饰符
java的访问权限修饰符有四种,根据权限由大到小的顺序为:public,protected,包访问权限(默认,没有修饰符),private. 根据修饰的东西不同,详细介绍如下: 1.修饰类的话分为两种 ...