(资料图)
设计模式六大原则
开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。
里氏替换原则:所有引用基类的地方必须能透明地使用其子类的对象.
依赖倒置原则:高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。
单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责。
接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
迪米特法则:一个对象应该对其他对象保持最少的了解。
1.单例模式:
特点: 使用单例模式, 则可以避免大量的new 操作消耗的资源
单例类不能直接实例化创建,而是只能由类本身实例化。因此,要获得这样的限制效果,构造函数必须标记为private,从而防止类被实例化。
需要一个私有静态成员变量来保存类实例和公开一个能访问到实例的公开静态方法。
在PHP中,为了防止他人对单例类实例克隆,通常还为其提供一个空的私有__clone()方法。
$_instance必须声明为静态的私有变量
构造函数和析构函数必须声明为私有,防止外部程序new 类从而失去单例模式的意义
getInstance()方法必须设置为公有的,必须调用此方法 以返回实例的一个引用
::操作符只能访问静态变量和静态函数
new对象都会消耗内存
使用场景:最常用的地方是数据库连接。
使用单例模式生成一个对象后, 该对象可以被其它众多对象所使用。
私有的__clone()方法防止克隆对象
登录后复制
2.工厂模式
工厂模式,工厂方法或者类生成对象,而不是在代码中直接new。
使用方法 new实例化类,每次实例化只需调用工厂类中的方法实例化即可。
优点:由于一个类可能会在很多地方被实例化。当类名或参数发生变化时,工厂模式可简单快捷的在工厂类下的方法中一次性修改,避免了一个个的去修改实例化的对象
Test1.php
test();function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\".$class.".php"; require $requireFile; }}Test1.php";return self::tt = new Test1();echo "创建对象
";return self::$tt;}}function echoHello(){ echo "Hello
"; }}Test.phpechoHello();$test = Test1::getInstance();$test->echoHello();$test = Test1::getInstance();$test->echoHello();$test = Test1::getInstance();$test->echoHello();function autoload1($class){ $dir = __DIR__; $requireFile = $dir."\".$class.".php"; require $requireFile; }}
登录后复制
举个例子,假设矩形、圆都有同样的一个方法,那么我们用基类提供的API来创建实例时,通过传参数来自动创建对应的类的实例,他们都有获取周长和面积的功能
width = $width;$this->height = $height;}public function getArea(){return $this->width* $this->height;}public function getCircumference(){return 2 * $this->width + 2 * $this->height;}}/**• 圆形*/class Circle implements InterfaceShape{private $radius;function __construct($radius){$this->radius = $radius;}public function getArea(){return M_PI * pow($this->radius, 2);}public function getCircumference(){return 2 * M_PI * $this->radius;}}/**• 形状工厂类*/class FactoryShape{public static function create(){switch (func_num_args()) {case1:return newCircle(func_get_arg(0));case2:return newRectangle(func_get_arg(0), func_get_arg(1));default:# code...break;}}}rect);echo "
";// object(Circle)#2 (1) { ["radius":"Circle":private]=> int(4) }circle);
登录后复制
3.注册模式
注册模式,解决全局共享和交换对象。已经创建好的对象,挂在到某个全局可以使用的数组上,在需要使用的时候,直接从该数组上获取即可。将对象注册到全局的树上。任何地方直接去访问。
登录后复制
4.策略模式
策略模式,将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。eg:假如有一个电商网站系统,针对男性女性用户要各自跳转到不同的商品类目,并且所有的广告位展示不同的广告。在传统的代码中,都是在系统中加入各种if else的判断,硬编码的方式。如果有一天增加了一种用户,就需要改写代码。使用策略模式,如果新增加一种用户类型,只需要增加一种策略就可以。其他所有的地方只需要使用不同的策略就可以。首先声明策略的接口文件,约定了策略的包含的行为。然后,定义各个具体的策略实现类。UserStrategy.php
strategy->showAd(); echo "
"; echo "Category"; $this->strategy->showCategory(); echo "
"; } function setStrategy(UserStrategy $strategy){ $this->strategy = $strategy; }}$page = new Page();if(isset($_GET["male"])){$strategy = new MaleUser();}else {$strategy = new FemaleUser();}strategy);$page->index();
登录后复制
总结:
通过以上方式,可以发现,在不同用户登录时显示不同的内容,但是解决了在显示时的硬编码的问题。如果要增加一种策略,只需要增加一种策略实现类,然后在入口文件中执行判断,传入这个类即可。实现了解耦。 实现依赖倒置和控制反转 (有待理解); 通过接口的方式,使得类和类之间不直接依赖。在使用该类的时候,才动态的传入该接口的一个实现类。如果要替换某个类,只需要提供一个实现了该接口的实现类,通过修改一行代码即可完成替换。
5.观察者模式
观察者模式(Observer),当一个对象状态发生变化时,依赖它的对象全部会收到通知,并自动更新(一个对象通过提供方法允许另一个对象即观察者 注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者)场景1:一个事件发生后,要执行一连串更新操作。传统的编程方式,就是在事件的代码之后直接加入处理的逻辑。当更新的逻辑增多之后,代码会变得难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件的主体代码。
场景2: 用户登录,需要写日志,送积分,参与活动等;使用消息队列,把用户和日志,积分,活动之间解耦合
观察者模式实现了低耦合,非侵入式的通知与更新机制。
observer_name;}function onListen($sender, $args){}}// 可被观察类abstract class Observable implements InterfaceObservable{protected $observers = array();public function addObserver(observerinstanceofInterfaceObserver){$this->observers[] = $observer;}}public function removeObserver(this->observersas $index => observer->getObserverName() === this->observers, $index, 1);return;}}}}// 模拟一个可以被观察的类class A extends Observable{public function addListener(this->observersas $observer){this, $listener);}}}// 模拟一个观察者类class B extends Observer{protected $observer_name = "B";public function onListen($sender, sender);echo "
";var_dump($args);echo "
";}}// 模拟另外一个观察者类class C extends Observer{protected $observer_name = "C";public function onListen($sender, sender);echo "
";var_dump($args);echo "
";}}a->addObserver(new B());$a->addObserver(new C());// 可以看到观察到的信息$a->addListener("D");// 移除观察者$a->removeObserver("B");// 打印的信息:// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }// string(1) "D"// object(A)#1 (1) { ["observers":protected]=> array(2) { [0]=> object(B)#2 (1) { ["observer_name":protected]=> string(1) "B" } [1]=> object(C)#3 (1) { ["observer_name":protected]=> string(1) "C" } } }// string(1) "D"
登录后复制
6.装饰器模式
装饰器模式, 根据运行时不同的情景动态地为某个对象调用前后添加不同的行一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重写实现类的方法,使用装饰器模式,仅需要在运行时添加一个装饰器对象即可实现,可以实现最大额灵活性
场景:
1.symfony 控制器中beforepost afterpost 中post提交前和提交后,对数据处理
2.当某一功能或方法draw,要满足不同的功能需求时,可以使用装饰器模式
/**• 输出一个字符串• 装饰器动态添加功能• Class EchoText*/class EchoText{protected $decorator = [];public function Index(){//调用装饰器前置操作$this->beforeEcho();echo "你好,我是装饰器。";//调用装饰器后置操作$this->afterEcho();}//增加装饰器public function addDecorator(Decorator $decorator){$this->decorator[] = $decorator;}//执行装饰器前置操作 先进先出原则protected function beforeEcho(){foreach ($this->decorator as $decorator)$decorator->before();}//执行装饰器后置操作 先进后出原则protected function afterEcho(){this->decorator);foreach ($tmp as $decorator)$decorator->after();}}/**• 装饰器接口• Class Decorator*/interface Decorator{public function before();public function after();}/**• 颜色装饰器实现• Class ColorDecorator*/class ColorDecorator implements Decorator{protected $color;public function __construct($color){$this->color = $color;}public function before(){echo "";}public function after(){echo "