设计模式简介
在软件开发过程中,经常出现的典型场景的典型解决方案,称为设计模式
面型对象 三大特性:多态 继承 封装
设计模式按目的分为三种类型:创建型,结构型,行为型
创建型
这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用新的运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。
- 单例模式【Singleton】
- 工厂模式【Factory】
- 抽象工厂模式【Abstract Factory】
- 建造者模式【Builder】
- 原型模式【Prototype】
结构型
这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。
- 适配器模式【Adapter】
- 桥接模式【Bridge】
- 合成模式【Composite】
- 装饰器模式【Decorator】
- 门面模式【Facade】
- 代理模式【Proxy】
- 享元模式【Flyweight】
行为型
这些设计模式特别关注对象之间的通信。
- 策略模式【Strategy】
- 模板方法模式【TemplateMethod】
- 观察者模式【Observer】
- 迭代器模式【Iterator】
- 责任链模式【ResponsibilityChain】
- 命令模式【Command】
- 备忘录模式【Memento】
- 状态模式【State】
- 访问者模式【Visitor】
- 中介者模式【Mediator】
- 解释器模式【Interpreter】
因为php是一门弱类型语言 所以以上的一些设计模式在php中是自动实现的 不需要通过代码实现 但是设计模式实现的思想都是一样的
设计模式优点:
1.降低代码的冗余量,写出优雅的代码
2.可以快速的帮助你读懂源码
3.提高代码的可扩展性
4.模块化代码,解决问题更加容易
设计模式原则
1. 开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
2. 里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.
3. 依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
4. 单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
5. 接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
6. 迪米特法则:一个对象应该对其他对象保持最少的了解。
单例模式[Singleton]
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。
这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
注意:
- 单例类只能有一个实例。
- 单例类必须自己创建自己的唯一实例。
- 单例类必须给所有其他对象提供这一实例。
//单例模式,一个类只能实例化一次
class Single
{
//私有化静态属性,保存类的实例对象
private static $single = [];
//私有化构造方法
private function __contruct()
{
}
//私有化克隆方法
private function __clone()
{
}
//入口
public static function getInstance( $classname , $arg = null)
{
//判断该类是否存在
if (!class_exists($classname))
{
return "class '{$classname}' is not found!";
}
//判断对象是否存在,不存在进行实例化
if( !isset(self::$single[$classname]) )
{
self::$single[$classname] = new $classname($arg);
}
return self::$single[$classname];
}
}
class test1
{
public $name;
function __construct($name)
{
$this->name = $name;
}
}
class test2
{
public $name;
function __construct($name)
{
$this->name = $name;
}
}
$obj1 = Single::getInstance('test1','test1');
$obj2 = Single::getInstance('test1','test2');
$obj3 = Single::getInstance('test2','test11111');
$obj4 = Single::getInstance('test2','test22222');
$obj5 = Single::getInstance('test3','test333');
var_dump($obj1,$obj2,$obj3,$obj4,$obj5);
/*输出:
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test1)[1]
public 'name' => string 'test1' (length=5)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test1)[1]
public 'name' => string 'test1' (length=5)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test2)[2]
public 'name' => string 'test11111' (length=9)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:
object(test2)[2]
public 'name' => string 'test11111' (length=9)
D:\myphp_www\PHPTutorial\WWW\demo.php:57:string 'class 'test3' is not found!' (length=27)
*/
工厂模式[Factory]
工厂模式要解决的问题:
- 在代码运行时候才知道要生成的对象类型
- 对象类型可能要扩充新产品类型
- 每个产品类型都可以定制特定的功能
采用简单工厂的优点是可以使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性;
缺点是可实例化的类型在编译期间已经被确定,如果增加新类型,则需要修改工厂,不符合OCP(开闭原则)的原则。
简单模拟一个超人
一个超人 具备超人的能力(就是超人技能:如飞行 射击 扔炸弹 暴力攻击等能力)
从面向对象设计:首先分析应该分为超人类(Superman) 和超人技能类(Flight Shot UltraBomb等)
为了规范编程写一个技能接口类(Ability) 用来规范超人技能类(同上) 当然超人也可以写一个超人接口来规范超人,这里就不写了
我要实现的是使用超人来拥有超人技能,我到底怎么实现的
<?php
//工厂类的使用
//超能力接口 作用:规范每个超人能力类
interface Ability
{
/**
* @Author shyn
* @DateTime 2017-12-20
* @param array $target [针对目标,可以使一个或多个,自己或他人]
* @return [type] [description]
* [超能力激活方法]
*/
public function activate(array $target);
}
//飞翔能力
class Flight implements Ability{
protected $speed;//速度
protected $holdtime;//飞行时间
protected $skill = '飞翔技能=';//技能描述
public function __construct($speed = 0, $holdtime = 0)
{
$this->speed = $speed;
$this->holdtime = $holdtime;
}
//激活该技能
public function activate(array $target = [])//参数可以忽略 保留待用
{
echo '超人飞行开始';
}
//输出该类实例(就是对象实例 如:new Flight;) 显示信息
public function __toString()
{
return $this->skill.'速度:'.$this->speed.' 飞翔时间:'.$this->holdtime;
}
}
//射击能力
class Shot implements Ability
{
protected $attack;//伤害
protected $range;//伤害范围
protected $skill = '射击技能=';//技能解说
public function __construct($attack = 0, $range = 0)
{
$this->attack = $attack;
$this->range = $range;
}
//激活技能
public function activate(array $target = [])
{
echo '超人射击开始';
}
public function __toString()
{
return $this->skill.'伤害:'.$this->attack.' 射击距离:'.$this->range;
}
}
//暴击能力
class Force implements Ability
{
protected $attack;//伤害
protected $strength;//力量
protected $range;//范围
protected $skill;//技能标签
public function __construct($attack = 0, $range = 0, $strength = 0)
{
$this->attack = $attack;
$this->range = $range;
$this->strength = $strength;
}
//激活暴击技能
public function activate(array $target = [])
{
echo '超人暴力攻击';
}
public function __toString()
{
$this->skill = '暴力能力=';
return $this->skill.'伤害:'.$this->attack.' 力量:'.$this->strength.' 范围'.$this->range;
}
}
//终极炸弹能力(扔炸弹)
class UltraBomb implements ability
{
protected $skill = '炸弹技能=';
protected $range;
protected $attack;
public function __construct($range = 0 , $attack = 0)
{
$this->range = $range;
$this->attack = $attack;
}
/*
* @Author shy
* @DateTime 2017-12-2109
* @param integer $bombRange [炸弹伤害范围 ]
* @param integer $attack [炸弹伤害程度 ]
* @return [type] [description ]
* [使用炸弹]
*/
public function throwBomb($range = 5, $attack = 10)
{
echo '炸弹范围'.$range.'米 伤害为:'.$attack;
}
public function activate(array $target = [])
{
echo '超人炸弹发射';
return $this;
}
public function __toString()
{
return $this->skill.'伤害:'.$this->attack.' 爆炸范围:'.$this->range;
}
}
//超人技能工厂类
class abilityFactory{
public function makeSkill($moduleName , $optoin)
{
switch($moduleName){
case 'Flight':
return new Flight($optoin[0], $optoin[1]);
case 'Force':
return new Force($optoin[0], $optoin[1], $optoin[2]);
case 'Shot':
return new Shot($optoin[0], $optoin[1]);
default :
throw new AbilityException("此 {$moduleName} 技能暂未开发");
}
}
}
//超人类
class Superman
{
public $power = [];//用来保存超人技能 超人会有多个技能所以用数组
//初始化时传入传入技能类的名称
public function __construct(array $ability)
{
//这里使用超人能力工厂类
//优点:
//1.方便对技能的管理 直接在工厂里添加我们扩展的其他超人技能
//2.我们的超人类不用直接依赖我们的超人技能类
//缺点:
//1.不用直接依赖我们的超人技能类但是依赖了工厂类
//2.工厂类改变的话我们的超人技能必将受到影响
//3.有没有更好的方法来 当然有 我们的神器:容器(可称为超级工厂)
//4.容器是什么 不是什么 a.你可以理解一个更厉害的类 b.解决了超人类对工厂类的依赖
$af = new abilityFactory();//实例化工厂类
foreach ($ability as $abilityName => $abilityOptions)
{
$this->power[] = $af->makeSkill($abilityName, $abilityOptions);
}
}
// 查看超人能力
public function __toString()
{
if(count($this->power)<1){
return '超人无能纳,还没任何技能';
}
foreach ($this->power as $key => $value)
{
echo $key.'=>'.$value.'<br/>';
}
return '超人共有'.count($this->power).'个技能<br />';
}
}
class AbilityException extends Exception
{
}
$ability = ['Flight'=>[1,4]];//填写超人技能类名不区分大小写对应 能力工厂类中case
$superman = new Superman($ability);
echo '<pre>';
echo $superman;//此时可以看到超人类中power 属性已经拥有该超人技能对象
$superman->power[0]->activate([]);//使用技能 看到这里完美 activate([]) 传递了一个空数组完全可以不需要 这里为了你可以传递技能参数故意添加的 可以自己试试搞一下 有些东西得练一下才好记得才明白
抽象工厂模式【Abstract Factory】
抽象工厂模式是对工厂模式的抽象,通俗来说,就是把工厂模式的结构分离出来成为能独立运行的个体。
拿工厂模式中的例子来说明:
现在有一个汽车工厂,它生产小汽车和巴士车,小汽车和巴士车都是由引擎、车身和轮子组成的。
在工厂模式中,我们把小汽车和巴士车作为汽车族群中的两个类别,生产引擎、车身和轮子为生产汽车的固定结构
再继续对工厂进行抽象,抽象出汽车工厂和巴士车工厂,并且让各工厂与各组件相关联,如图:
//生产引擎的标准
interface engineNorms{
function engine();
}
class carEngine implements engineNorms{
public function engine(){
return '汽车引擎';
}
}
class busEngine implements engineNorms{
public function engine(){
return '巴士车引擎';
}
}
//生产车身的标准
interface bodyNorms{
function body();
}
class carBody implements bodyNorms{
public function body(){
return '汽车车身';
}
}
class busBody implements bodyNorms{
public function body(){
return '巴士车车身';
}
}
//生产车轮的标准
interface whellNorms{
function whell();
}
class carWhell implements whellNorms{
public function whell(){
return '汽车轮子';
}
}
class busWhell implements whellNorms{
public function whell(){
return '巴士车轮子';
}
}
//工厂标准
interface factory{
static public function getInstance($type);
}
//汽车工厂
class carFactory implements factory{
static public function getInstance($type){
$instance='';
switch($type){
case 'engine':
$instance=new carEngine();
break;
case 'body':
$instance=new carBody();
break;
case 'whell':
$instance=new carWhell();
break;
default:
throw new Exception('汽车工厂无法生产这种产品');
}
return $instance;
}
}
//巴士车工厂
class busFactory implements factory{
static public function getInstance($type){
$instance='';
switch($type){
case 'engine':
$instance=new busEngine();
break;
case 'body':
$instance=new busBody();
break;
case 'whell':
$instance=new busWhell();
break;
default:
throw new Exception('巴士车工厂无法生产这种产品');
}
return $instance;
}
}
$car['engine']=carFactory::getInstance('engine')->engine();
$car['body']=carFactory::getInstance('body')->body();
$car['whell']=carFactory::getInstance('whell')->whell();
print_r($car);
$bus['engine']=busFactory::getInstance('engine')->engine();
$bus['body']=busFactory::getInstance('body')->body();
$bus['whell']=busFactory::getInstance('whell')->whell();
print_r($bus);
抽象工厂模式将工厂模式进行抽象,可以使得抽象出来的新结构更加的灵活。例如,若生产车身需要一个喷漆的动作,在工厂模式中,我们需要对整体结构进行更改,而抽象工厂中,只需要对生产车身进行更改就ok了。
抽象工厂模式同样具有工厂模式对结构要求高的缺点,整体结构的扩展或精简将变得更加的烦杂,所以使用抽象工厂模式时,对等级结构的划分是非常重要的。
以上部分内容转自
https://www.cnblogs.com/shynshyn/p/8075299.html
https://my.oschina.net/botkenni/blog/1603660
https://blog.csdn.net/phenixsoul/article/details/8493764