PHP设计模式
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
目录
迭代器模式Iterator(生成器模式generator是迭代器的一种即迭代器的实现)
一、使用设计模式目的
- 重用性 (相同功能的代码不用多次编写)
- 可读性 (编程规范性, 便于其他程序员的阅读和理解)
- 可扩展性 (当需要增加新的功能时非常的方便称为可维护)
- 可靠性 (当我们增加新的功能后对原来的功能没有影响)
- 使程序呈现高内聚低耦合的特性
二、设计模式的七大原则
- 单一职责原则一个类应该只负责一项职责
- 接口隔离原则一个类对另一个类的依赖应该建立在最小的接口上。客户端不应该依赖它不需要的接口
- 依赖倒转(倒置)原则对抽象进行编程不要对实现进行编程。程序要依赖于抽象接口不要依赖于具体实现
- 里氏替换原则子类可以扩展父类的功能但不能改变原有父类的功能
- 开闭原则又叫开放封闭原则。对扩展开发对修改关闭
- 迪米特法则又叫最少知识原则。一个类对于其他类知道的越少越好
- 合成复用原则又叫组合/聚合复用原则。通过将已有的对象纳入新对象中作为新对象的成员对象来实现的新对象可以调用已有对象的功能从而达到复用。软件复用时要尽量先使用组合或者聚合等关联关系来实现其次才考虑使用继承关系来实现
三、创建型模式构建型模式
-
1、单例模式
单例模式的主要特点是【三私一公】
- 私有的静态成员变量用来保存类的唯一实例
- 私有的构造函数防止外部程序new一个对象从而失去单例的意义
- 私有的克隆函数防止对象被克隆
- 公共的静态方法(通常命名为getInstance)从而返回唯一实例的一个引用。
代码实例
<?php
namespace App\Services;
class DanLiService
{
private static $instance = null;
private function __construct()
{
}
private function __clone()
{
// TODO: Implement __clone() method.
}
public static function getInstance()
{
if(empty( self::$instance )){
self::$instance = new self();
}
return self::$instance;
}
public function testOne()
{
return '实现1';
}
public function testTwo()
{
return '实现2';
}
}
$obj = DanLiService::getInstance();
print_r($obj->testOne());
print_r($obj->testTwo());
2、工厂模式
工厂模式一共分3三种简单工厂模式、工厂方法模式、抽象工厂模式
在平时写代码过程中构建对象最常用的方式是 new 一个对象。这属于一种硬编码。每 new 一个对象相当于调用者就知道了一个类增加了类与类之间的联系不利于程序的松耦合。其实构建过程可以被封装起来工厂模式便是用于封装对象的设计模式。
-
2.1、工厂模式——简单工厂模式
例如
当我们需要一个苹果时我们需要知道苹果的构造方法需要一个梨子时需要知道梨子的构造方法。
更好的实现方式是有一个水果工厂我们告诉工厂需要什么种类的水果水果工厂将我们需要的水果制造出来给我们就可以了。这样我们就无需知道苹果、梨子是怎么种出来的只用和水果工厂打交道即可。
-
简单工厂模式的代码实例
/**
* 水果工厂类
*/
class FruitFactory
{
/**
* 通知不同水果的生产车间
* @param string $name [车间名字]
* @return object
*/
public static function noticeWorkShop( $name )
{
switch($name){
//苹果
case 'apple':
return new Apple();
//梨
case 'pear':
return new Pear();
default:
throw new \Exception( '抱歉我们工厂不生产该种类水果。' );
}
}
}
/**
* 苹果车间
*/
class Apple implements Product
{
public function __construct()
{
}
public function eat()
{
// TODO: Implement sound() method.
echo '我是苹果';
}
}
/**
* 梨车间
*/
class Pear implements Product
{
public function __construct()
{
}
public function eat()
{
// TODO: Implement sound() method.
echo '我是梨';
}
}
/**
* 水果产品接口类该类中定义的方法都是子类所必须实现的方法
*/
interface Product
{
/**
* @return mixed
*/
public function eat();
}
//调用实例
try{
$product = FruitFactory::noticeWorkShop('apple');
$obj = $product->eat();
print_r($obj);die;
}catch(\Exception $e) {
echo $e->getMessage();
}
-
2.2、工厂模式——工厂方法模式
工厂方法模式是简单工厂的升级版在原有的基础上对工厂进行一个抽象的升级我们不再提供一个统一的工厂类来创建所有的对象而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。
-
工厂方法模式的代码实例
/**
* 苹果工厂类,专门负责加工苹果
*/
class AppleFactory
{
public function __construct()
{
}
public function create(){
return new Apple();
}
}
/**
* 梨工厂,专门负责加工梨
*/
class PearFactory
{
public function __construct()
{
}
public function create()
{
return new Pear();
}
}
//调用实例
try{
//调用苹果工厂
$appleFactory = new AppleFactory();
$appleObj = $appleFactory->create();
$appleObj->eat();
//调用梨工厂
$pearFactory = new PearFactory();
$pearObj = $pearFactory->create();
$pearObj->eat();
die;
}catch(\Exception $e) {
echo $e->getMessage();
}
有没有发现上述代码和直接 new 出Apple对象和Pear对象有什么区别感觉上没什么区别。不过上文提到了工厂是为了减少类与类之间的耦合让调用者尽可能少的和其他类打交道。用简单工厂模式我们只需要知道 FruitFactory无需知道 Apple 、Pear 类很容易看出耦合度降低了。但用工厂方法模式调用者虽然不需要和 Apple 、Pear 类打交道了但却需要和 AppleFactory、PearFactory 类打交道。有几种水果就需要知道几个工厂类耦合度完全没有下降甚至还增加了代码量
还是有些优点的
- 当某个产品构建相当复杂时工厂将构建过程封装起来调用者可以很方便的使用。
- 当生产的水果产品越来越多时工厂类不会变成超级类工厂类会越来越多但不会越来越大不会变得臃肿这就符合【单一职责原则】
-
2.3、工厂模式——抽象工厂模式
抽象工厂模式是工厂方法模式的进一步优化
/**
* 抽象工厂接口
*/
interface InterfaceFactory
{
/**
* @return mixed
*/
public function create();
}
/**
* 苹果工厂类,继承工厂接口
*/
class AppleFactory implements InterfaceFactory
{
public function create(){
return new Apple();
}
}
/**
* 梨工厂类继承工厂接口
*/
class PearFactory implements InterfaceFactory
{
public function create()
{
return new Pear();
}
}
此时调用者可以将 AppleFactory 和 PearFactory 统一作为 InterfaceFactory 对象使用
//调用者
try{
$appleFactory = new AppleFactory();
$objApple = $appleFactory->create();
$objApple->eat();
}catch(\Exception $e) {
echo $e->getMessage();
}
- 由于客户端只和 InterfaceFactory 打交道了调用的是接口中的方法使用时根本不需要知道是在哪个具体工厂中实现的这些方法这就使得替换工厂变得非常容易。
- 抽象工厂模式很好的发挥了开闭原则、依赖倒置原则但缺点是抽象工厂模式太重了如果 InterfaceFactory 接口需要新增功能则会影响到所有的具体工厂类。使用抽象工厂模式替换具体工厂时只需更改一行代码但要新增抽象方法则需要修改所有的具体工厂类。所以抽象工厂模式适用于增加同类工厂这样的横向扩展需求不适合新增功能这样的纵向扩展。
3、原型模式
- 原型模式Prototype Pattern与工厂模式类似都是用来创建对象的。原型模式是利用克隆来生成一个大对象减少创建new时的初始化等操作占用开销原型模式仅需内存拷贝
- 为什么需要原型模式
- 有些时候我们需要创建多个类似的大对象。如果直接通过new对象开销很大而且new完还得进行重复的初始化工作。可能把初始化工作封装起来的但是对于系统来说你封不封装初始化工作还是要执行。
- 原型模式则不同原型模式是先创建好一个原型对象然后通过clone这个原型对象来创建新的对象这样就免去了重复的初始化工作系统仅需内存拷贝即可。
-
原型模式的代码实例
定义一个原型接口
interface Prototype{
//浅拷贝
public function shallowCopy();
//深拷贝
public function deepCopy();
}
定义一个具体原型
class ConcretePrototype implements Prototype
{
private $_name;
public function __construct($name)
{
$this->_name = $name;
}
public function setName($name)
{
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
//浅拷贝
public function shallowCopy()
{
// TODO: Implement shallowCopy() method.
return clone $this;
}
//深拷贝
public function deepCopy()
{
// TODO: Implement deepCopy() method.
$serializeObj = serialize($this);
$cloneObj = unserialize($serializeObj);
return clone $cloneObj;
}
}
定义一个用户测试原型
class Demo{
public $string;
}
class UserPrototype
{
//浅拷贝
public function shallow()
{
$demo = new Demo();
$demo->string = "susan";
$object_shallow_first = new ConcretePrototype($demo);
$object_shallow_second = $object_shallow_first->shallowCopy();
var_dump($object_shallow_first->getName());
echo '<br/>';
var_dump($object_shallow_second->getName());
echo '<br/>';
$demo->string = "sacha";
var_dump($object_shallow_first->getName());
echo '<br/>';
var_dump($object_shallow_second->getName());
echo '<br/>';
}
//深拷贝
public function deep()
{
$demo = new Demo();
$demo->string = "Siri";
$object_deep_first = new ConcretePrototype($demo);
$object_deep_second = $object_deep_first->deepCopy();
var_dump($object_deep_first->getName());
echo '<br/>';
var_dump($object_deep_second->getName());
echo '<br/>';
$demo->string = "Demo";
var_dump($object_deep_first->getName());
echo '<br/>';
var_dump($object_deep_second->getName());
echo '<br/>';
}
}
调用
try{
$user = new UserPrototype();
$user->shallow();
echo "</BR>";
$user->deep();;
}catch(\Exception $e) {
echo $e->getMessage();
}
调用测试结果
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "susan" }
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "susan" }
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "sacha" }
object(App\Services\Demo)#1229 (1) { ["string"]=> string(5) "sacha" }
object(App\Services\Demo)#1236 (1) { ["string"]=> string(4) "Siri" }
object(App\Services\Demo)#1237 (1) { ["string"]=> string(4) "Siri" }
object(App\Services\Demo)#1236 (1) { ["string"]=> string(4) "Demo" }
object(App\Services\Demo)#1237 (1) { ["string"]=> string(4) "Siri" }
浅拷贝
赋值时引用赋值相当于取了一个别名。对其中一个修改会影响另一个 对象作为参数传递时也是引用传递
深拷贝
赋值时值完全复制完全的copy对其中一个作出改变不会影响另一个
4、建造者模式
核心思想是将一个复杂对象的构造与它的表示分离使同样的构建过程可以创建不同的表示这样的设计模式被称为建造者模式
/**
* 抽象接口
*/
interface InterfaceBuilder
{
//创建车辆
public function createVehicle();
//添加车门
public function addDoors();
//添加引擎
public function addEngine();
//添加车轮
public function addWheel();
//获取车辆
public function getVehicle();
}
实现所有方法的自行车类
class BikeBuilder implements InterfaceBuilder
{
protected $bike;
public function createVehicle()
{
$this->bike[] = '创建自行车建造任务';
}
public function addDoors()
{
$this->bike[] = '建造了车门';
}
public function addEngine()
{
$this->bike[] = null;
}
public function addWheel()
{
$this->bike[] = '建造了车轮';
}
public function getVehicle()
{
return $this->bike;
}
}
实现所有方法的轿车类
class CarBuilder implements InterfaceBuilder
{
protected $car;
public function createVehicle()
{
$this->car[] = '创建小轿车建造任务';
}
public function addDoors()
{
$this->car[] = '建造了车门';
}
public function addEngine()
{
$this->car[] = '建造了引擎发动机';
}
public function addWheel()
{
$this->car[] = '建造了车轮';
}
public function getVehicle()
{
return $this->car;
}
}
按照实际需要分别调用Bike类和Car类实现所有功能聚合
class Index
{
public $vecicle;
public function getVe($type = 1)
{
if ($type == 1) { //Bike
$this->vecicle = new BikeBuilder();
} else if ($type == 2) { //Car
$this->vecicle = new CarBuilder();
}
$this->vecicle->createVehicle();
$this->vecicle->addDoors();
$this->vecicle->addEngine();
$this->vecicle->addWheel();
$this->vecicle->getVehicle();
return $this->vecicle;
}
}
四、结构型模式
-
适配器模式
-
桥接模式
-
装饰模式
-
组合模式
-
外观模式
-
享元模式
-
代理模式
五、行为型模式
-
模版方法模式
-
命令模式
-
访问者模式
-
迭代器模式Iterator(生成器模式generator是迭代器的一种即迭代器的实现)
-
观察者模式
-
中介者模式
-
备忘录模式、
-
解释器模式Interpreter
-
状态模式
-
策略模式
-
职责链模式(责任链模式)