设计模式的一些小整理
💻设计模式
设计模式概述
设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样。
模式的经典定义:每个模式都描述了一个在我们的环境中不断出现的问题,然后描述了该问题的解决方案的核心,通过这种方式,我们可以无数次地重用那些已有的解决方案,无需再重复相同的工作。即模式是在特定环境中解决问题的一种方案
现在有两派,有的人建议使用设计模式,有的人不建议使用设计模式!
解决代码的耦合度
耦合度越低越好
高内聚低耦合(对内要高内聚,对外要低耦合)
设计模式不分语言。php是世界上最优美的语言
1 单例模式
这个类只能创建一个对象
php的应用主要在于数据库的应用,一个应用会出现大量的数据库操作,使用单例模式,可以避免大量的操作消耗的资源
步骤:
-
构造函数需要标记为private
-
保存类实例的静态成员变量
-
获取实例的公共的静态方法
class Dog
{
//设置一个静态的成员属性来保存单例对象
static private $instance;
//将构造函数私有化
private function getInstance()
{
if(self::$instance){
self::$instances = new self();
}
return self::$instance;
}}
//调用的时候就调用这个函数
$dog1 = Dog::getInstance();
$dog2 = Dog::getInstance();
if ($dog1 === $dog2) {
echo '这是同一条狗
';
} else {
echo '这不是同一条狗
';
}
2 简单工厂、标准工厂
接口中定义一些方法
实现接口的类实现这些方法
工厂类:用以实例化对象
优点:为系统结构提供了灵活的动态扩展机制。方便维护
步骤
1、根据类调用一个静态方法,传递一个你想要创造什么样对象的额参数
就可以获得这个类
2、有一个接口
3、各个类型实现这些接口
/***************简单工厂模式***********************/
interface Skill
{
function family();
function buy();
}
class Human implements Skill
{
function family()
{
echo '人族在辛辛苦苦的伐木累<br />';
}
function buy()
{
echo '人族买了一个国王祭坛<br />';
}
}
class JingLing implements Skill
{
function family()
{
echo '精灵族在绕树转圈,吸取大树的日月精华<br />';
}
function buy()
{
echo '精灵族买了一个战争古树<br />';
}
}
class Animal implements Skill
{
function family()
{
echo '兽族在卯足了劲与树对干<br />';
}
function buy()
{
echo '兽族买了一个灵族祭坛<br />';
}
}
class NoDie implements Skill
{
function family()
{
echo '不死族在大口大口的吃树<br />';
}
function buy()
{
echo '不死族买了一个墓地<br />';
}
}
#根据你给的类型switch出你要new的对象
class Factory
{
static function makeHero($type)
{
switch ($type) {
case 'humans':
return new human();
break;
case 'jingling':
return new JingLing();
break;
case 'animal':
return new Animal();
break;
case 'nodie':
return new NoDie();
break;
}
}
}
#调用的时候是调用工厂里面的静态函数
$human = Factory::makeHero('animal');
echo $human->family();
3 工厂模式
工厂方法模式核心是工厂类不再负责所有对象的创建,而是将具体创建的工作交给子类去做,成为一个抽象工厂角色,它仅负责给出具体工厂类必须实现的接口,而不接触哪一个产品类应当被实例化这种细节
1:首先给工厂一个接口标准
2:然后各种类型去继承这些接口
3:然后又一个工厂接口,静态的方法
4:各个工厂自己去实现自己的接口来创造手机
5:最终想要什么类型的,就用该类型自己的工厂去调用静态函数去实现
interface Tell
{
function call();
function recieve();
}
class xiaoMi implements Tell
{
function call()
{
echo '我在用小米手机打电话'.'<br/>';
}
function recieve()
{
echo '我在用小米手机接电话'.'<br/>';
}
}
class meiZu implements Tell
{
function call()
{
echo '我在用meiZu手机打电话'.'<br/>';
}
function recieve()
{
echo '我在用meiZu手机接电话'.'<br/>';
}
}
/***********************************************/
interface Factory
{
static function makePhone();
}
class xiaomiFactory implements Factory
{
function makePhone()
{
return new xiaoMi();
}
}
class meizuFactory implements Factory
{
function makePhone()
{
return new meiZu();
}
}
/******************************************/
$phone = meizuFactory::makePhone();
echo $phone->recieve();
4 观察者模式
涉及到两个类:
@-@一个是被观察者
1、添加观察者
2、删除观察者
3、发送通知
@-@一个是观察者
1、做出反应即可
在php中:用户注册(收到邮件,收到短信,或者收到其他信息)
它是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;
观察者模式提供了避免组件之间紧密耦合的另一种方法。
官方接口
SplSubject
attach 添加观察者
detach 删除观察者
notify 通知
SplOberser
update 做出响应
/**************被观察者*****************************/
class SuperBoy
{
#我可以有自己的观察者,放在数组里
public $observers = [];
#添加观察者的时候会传进来一个人是对象,然后把这个人放在数组里
function addObserver($observer)
{
$this->observers[] = $observer;
}
#删除观察者的时候也是找到传入的这个人的键删掉
function deleteObserver($observer)
{
$key = array_search($observer,$this->observers);
unset($this->observers[$key]);
}
// 有通知观察者的做法,也就是让观察者做出反应
function notice()
{
foreach ($this->observers as $observer)
{
// 让这些对象分别去调用做出反应的方法
foreach ($this->observers as $observer) {
$observer->findYou();
}
}
}
function kf()
{
$this->notice();
}
}
// 观察者只需要做出反应即可
class Girl
{
function findYou()
{
echo '老娘就知道你在外面不老实,我哪里不如她<br />';
}
}
/************************************************/
$hututu = new Girl();
$huchunchun = new Girl();
$lihui = new Girl();
$obj = new SuperBoy();
$obj->addObserver($hututu);
$obj->addObserver($huchunchun);
$obj->addObserver($lihui);
$obj->kf();
5 适配器模式
生活中就有很多适配器 电源适配器 就是里面的变压器 220v
可将一个类的接口转换成客户希望的另外一个接口,使得原本不兼容的接口能够一起工作。通俗的理解就是将不同接口适配成统一的接口
1:当一个类实现外面的接口的时候,会通过传递一个对象,调用这个对象的方法
2:在接口函数里面调用对象的方法
interface SuperMan
{
function cook();
function writePhp();
}
class Mans
{
function cook()
{
echo __CLASS__ . '<br/>';
echo "我会做宫保鸡丁";
}
}
/***************这里是核心******************/
class CodeMonkey implements SuperMan
{
public $Man;
function __construct($Man)
{
$this->Man = $Man;
}
function cook ()
{
$this->Man->cook();
}
function writePhp()
{
echo '我不仅会写php代码,我还会java、oc、c++、c#、c、go、js<br />';
}
}
$xiaohuihui = new Mans();
$xiang = new CodeMonkey($xiaohuihui);
$xiang->cook();
$xiang->writePhp();
6 策略模式
(1)多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
(2)需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
(3)对客户隐藏具体策略(算法)的实现细节,彼此完全独立。
(4)客户端必须知道所有的策略类,并自行决定使用哪一个策略类,策略模式只适用于客户端知道所有的算法或行为的情况。
(5)策略模式造成很多的策略类,每个具体策略类都会产生一个新类。
优点:
1、策略模式提供了管理相关的算法族的办法
2、算法封闭在独立的Strategy类中使得你可以独立于其Context改变它
3、使用策略模式可以避免使用多重条件转移语句
7 门面模式
优点
1、它对客户屏蔽了子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便
2、实现了子系统与客户之间的松耦合关系
3、如果应用需要,它并不限制它们使用子系统类。因此可以在系统易用性与能用性之间加以选择
适用场景
1、为一些复杂的子系统提供一组接口
2、提高子系统的独立性
3、在层次化结构中,可以使用门面模式定义系统的每一层的接口
interface JiPai
{
function want();
function cook();
}
class XXJipai
{
function naoyou()
{
echo '脑油味鸡排<br />';
}
function biti()
{
echo '鼻涕味鸡排<br />';
}
}
class People implements JiPai
{
public $XXJipai;
function __construct()
{
$this->XXJipai = new XXJipai();
}
function want()
{
$this->XXJipai->naoyou();
}
function cook()
{
$this->XXJipai->biti();
}
}
$test = new People();
$test->want();
$test->cook();
门面模式就是给你两个方法当门:这两个方法里面有你要执行的操作,于是你只需要调用这个门方法就可以了
门方法里面的函数是用对象调用的,对象是里面的成员属性
8 DI依赖注入
(Ioc反转控制)(Dependency Injection)
说白了就是传递一个参数进来,只不过这个参数是强制类型
这样就不好了,所有的全部固定了。
interface Roller
{
function roll();
}
class MiQiLin implements Roller
{
function roll()
{
echo '米其林轮胎在滚动<br />';
}
}
class BeiNaiLi implements Roller
{
function roll()
{
echo '倍耐力轮胎在滚动<br />';
}
}
/*********************************************/
interface Runner
{
function run();
}
class HongGuang implements Runner
{
private $tai;
function __construct(Roller $tai)
{
$this->tai = $tai;
}
function run()
{
$this->tai->roll();
echo '神车五菱宏光在高速公路上和宝马飙车<br />';
}
}
class BMW implements Runner
{
private $tai;
function __construct(Roller $tai)
{
$this->tai = $tai;
}
function run()
{
$this->tai->roll();
echo '宝马在高速公路上飙车<br />';
}
}
/*****************************************/
class Xiang
{
private $car;
function __construct(Runner $car)
{
$this->car = $car;
}
function travel()
{
$this->car->run();
echo '我带着别人的媳妇私奔了<br />';
}
}
//$tai = new MiQiLin();
//$tai = new BeiNaiLi();
//$car = new BMW($tai);
//$car = new HongGuang($tai);
$xiang = new Xiang(new BMW(new MiQiLin()));
$xiang->travel();
9 容器
容器:在我们的依赖注入里面需要注入大量的对象实例,然后呢,总不能全部实例化好吧,所以呢,这个时候,我们需要一个容器把这些实例放到里面,需要用的时候取出来
class Container
{
static public $things = [];
//往容器里面放东西
static public function bind($name, Closure $method) //限定类型为匿名函数
{
if(!isset(self::$things[$name]))
{
self::$things[$name] = $method; //这里绑定匿名函数是不执行的亲
}
}
//在容器里面取出来用
static public function make($name)
{
if(isset(self::$things[$name]))
{
$func = self::$things[$name];
$func();
}
}
}
Container::bind('jinLong', function(){
echo '你看我是两条金龙鱼<br>';
});
Container::bind('xiaojie', function(){
echo '我要吃了哪条金龙鱼<br>';
});
Container::make('jinLong');
Container::make('xiaojie');
10 反射
主要是指程序可以访问,检测和修改它本身状态或行为的一种能力,并能根据自身行为的状态和结果,调整或修改应用所描述行为的状态和相关的语义
通过反射机制访问对象的属性,方法,构造方法等
<?php
/**
* 你看我是一个注释
* @author
* @concat 3wfindme@gmail.com
*/
class XiaoJie
{
public $name = 'xiaojiejie';
/**
* 这是一个方法的注释
* @param $where string
* @param $how string
*/
public function zuo($where, $how)
{
echo '小杰想做于是乎他就做了。。。';
}
public function shui()
{
echo '小杰说做累了就呼呼睡觉<br>';
}
}
// $reflection = new ReflectionClass('XiaoJie');
// $method = $reflection->getMethods();
// $doc = $reflection->getDocComment();
// var_dump($reflection->getMethod('zuo'));
// var_dump($doc);
// var_dump($method);
// var_dump($reflection);
$r = new ReflectionMethod(new XiaoJie(), 'zuo');
var_dump($r->getParameters());
var_dump($r->getDocComment());