一、多态
多态相对封装与继承,理解稍微复杂一些,更重要的是通过PHP,Java多态的不同体现,体会静态语言与动态语言的巨大差异,而这个差异巨大,影响到设计模式
对于动态语言,不可照搬java,c++中的设计模式
多态是一种生物学上的概念,指同一特种的多种表达形态,如:西伯利亚虎一般重210-260公斤,而孟加拉虎一般180-230公斤
在面向对象中,指某种对象实例中不同的表现形态
多态特点,在静态语言中体现更为明显
<?php
abstract class Tiger
{
public abstract function climb();
}
class XTiger extends Tiger
{
public function climb()
{
echo '摔下来';
}
}
class MTiger extends Tiger
{
public function climb()
{
echo '爬到树顶';
}
}
class Cat
{
public function climb()
{
echo '飞到天上';
}
}
class Client
{
public static function call($animal)
{
$animal->climb();
}
}
Client::call(new XTiger());
Client::call(new MTiger());
Client::call(new Cat());
摔下来爬到树顶飞到天上
对于PHP来说可以不指定用户类型,但是对Java来说,传参必须指定特定类型
二、设计模式的六大原则
开放封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭
里氏替换原则:所有引用基类的地方必须能透明的使用其子类的对象
依赖倒置原则:高层模块不应该依赖低层模块,二则都应该依赖其抽象;抽象不应该依赖细节,细节应该依赖抽象
单一职责原则:不要存在多于一个导致类变更的原因。通俗的说,即一个类只负责一项职责
接口隔离原则:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。
迪米特法则:一个对象对象应该对其他对象保持最少的了解
三、工厂模式
在Java可以直接打jar包来让别人调用,PHP中不能打包,所以尽可能让别人少知道你的实现而只管调用就行
特点:将调用对象与创建对象分离,调用者直接向工厂请求,减少代码的耦合.提高系统的可维护性与可扩展性。
应用场景:提供一种类,具有为您创建对象的某些方法,这样就可以使用工厂类创建对象,而不直接使用new。这样如果想更改创建的对象类型,只需更改该工厂即可。
1.简单工厂
<?php
//共同接口
interface db
{
function conn();
}
//服务器开发不知道会被谁调用
class dbmysql implements db
{
public function conn()
{
echo '连上了Mysql';
}
}
class dbsqlite implements db
{
public function conn()
{
echo '连上了sqlite';
}
}
class Factory
{
public static function createDB($type)
{
if ($type == 'mysql') {
return new dbmysql();
} else if ($type == 'sqlite'){
return new dbsqlite();
}else{
throw new Exception('Error db type',1);
}
}
}
$mysql= Factory::createDB('mysql');
$mysql->conn();
$mysql= Factory::createDB('sqlite');
$mysql->conn();
如果新增Oracle类怎么办?
服务器要改Factory的内容(在java,c++改后还得再编译)
在面向对象设计法则中,重要的开闭原则....(对于修改是封闭的,对于扩展是开放的)
2.工厂方法
<?php
//共同接口
interface db
{
function conn();
}
interface Factory
{
function createDB();
}
//服务器开发不知道会被谁调用
class dbmysql implements db
{
public function conn()
{
echo '连上了Mysql';
}
}
class dbsqlite implements db
{
public function conn()
{
echo '连上了sqlite';
}
}
class mysqlFactory implements Factory
{
public function createDB()
{
return new dbmysql();
}
}
class sqliteFactory implements Factory
{
public function createDB()
{
return new dbmysql();
}
}
//客户端开发
$fact = new mysqlFactory();
$mysql = $fact->createDB();
$mysql->conn();
$fact = new sqliteFactory();
$sqlite = $fact->createDB();
$sqlite->conn();
//======服务器端添加oracle类========
//前面代码不用改
class dboracle implements db
{
public function conn()
{
echo '连上了oracle';
}
}
class oracleFactory implements Factory
{
public function createDB()
{
return new dboracle();
}
}
$fact = new oracleFactory();
$oracle = $fact->createDB();
$oracle->conn();
连上了Mysql连上了Mysql连上了oracle
四、单例模式
特点:三私一公:私有的静态变量(存放实例),私有的构造方法(防止创建实例),私有的克隆方法(防止克隆对象),公有的静态方法(对外界提供实例)
应用场景:程序应用中,涉及到数据库操作时,如果每次操作的时候连接数据库,会带来大量的资源消耗。可以通过单例模式,创建唯一的数据库连接对象
<?php
//第一步,普通类
//第二部,封锁new操作,构造方法改成protected
//第三步,留个接口new对象,创建一个静态方法可以new自身
//第四步,判断实例,如果已经被创建过就不创建了
//第五步,用final,防止继承时被修改权限,构造方法前加final,构造方法不能被覆盖;类前加final则类不能被继承
//第六步,禁止clone
class sigle
{
protected static $ins = null;
public static function getIns()
{
if (self::$ins === null) {
self::$ins = new self();
}
return self::$ins;
}
final protected function __construct()
{
}
//封锁clone
final protected function __clone()
{
}
}
$s1 = sigle::getIns();
//$s2 = clone $s1;
$s3 = sigle::getIns();
if($s1===$s3) echo '是一个对象';
else echo '不是一个对象';
是一个对象
五、观察者模式
观察者模式是挺常见的一种设计模式,使用得当会给程序带来非常大的便利,使用得不当,会给后来人带来一种难以维护的想法。
使用场景:用户登录,需要写日志、送积分、参与活动等使用消息队列,把用户和日志、积分、活动之间解耦合
什么是观察者模式?一个对象通过提供方法允许另一个对象即观察者注册自己,是本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者
这些观察者使用该信息执行的操作与可观察的对象无关。结果时对象可以相互对话,而不必了解原因。
观察者模式是一种事件系统,意味着这一模式允许某个类观察另一个类的状态,当被观察的类状态发生改变的时候,观察类可以收到通知并且做出相应的动作;观察者模式为您提供了避免组件之间的紧密耦合
<?php
class user implements SplSubject
{
public $lognum;
public $hobby;
protected $observers = null;
public function __construct($hobby)
{
$this->lognum = rand(1,10);
$this->hobby = $hobby;
$this->observers = new SplObjectStorage();//记录观察你的对象
}
public function login()
{
//操作session....
$this->notify();
}
public function attach(SplObserver $observer)
{
$this->observers->attach($observer);
}
public function detach(SplObserver $observer)
{
$this->observers->detach($observer);
}
public function notify()
{
$this->observers->rewind();//把指针指到头上去
while ($this->observers->valid()) {
$observer = $this->observers->current();//获得当前的对象
$observer->update($this);
$this->observers->next();
}
}
}
class secrity implements SplObserver
{
public function update(SplSubject $subject)
{
if ($subject->lognum < 3) {
echo '这是第' . $subject->lognum . '次登录';
} else {
echo '这是第' . $subject->lognum . '次登录,异常';
}
}
}
class ad implements SplObserver
{
public function update(SplSubject $subject)
{
if ($subject->hobby =='sports') {
echo '运动' ;
} else {
echo '好好学习';
}
}
}
//实施观察
$user=new user('sports');
$user->attach(new secrity());
$user->attach(new ad());
$user->login();
六、责任链模式
责任链模式是一种行为型模式,它允许多个对象将请求沿着处理链传递,直到有一个对象处理该请求为止。
<?php
$lev = 2; //1,2,3都可
class board
{
protected $power = 1;
protected $top = 'admin';
public function process($lev)
{
if ($lev <= $this->power) {
echo '版主删帖';
} else {
$top = new $this->top;
$top->process($lev);
}
}
}
class admin
{
protected $power = 2;
protected $top = 'police';
public function process($lev)
{
if ($lev <= $this->power) {
echo '管理员封号';
} else {
$top = new $this->top;
$top->process($lev);
}
}
}
class police
{
protected $power;
protected $top = null;
public function process($lev)
{
echo '抓起来';
}
}
$judge=new board();
$judge->process($lev);
七、策略模式
将一组特定的行为和算法封装成类,以适应某些特定的上下文环境。
使用场景:(个人理解),策略模式是依赖注入,控制反转的基础
和工厂模式非常像,工厂模式是直接根据返回的实例去操作,策略模式里根据不同的参数返回的对象返回给父类了,人不必直接去碰得到的子对象
<?php
interface Math
{
public function calc($op1, $op2);
}
class MathAdd implements Math
{
public function calc($op1, $op2)
{
return $op1 + $op2;
}
}
class MathSub implements Math
{
public function calc($op1, $op2)
{
return $op1 - $op2;
}
}
class MathMul implements Math
{
public function calc($op1, $op2)
{
return $op1 * $op2;
}
}
class MathDiv implements Math
{
public function calc($op1, $op2)
{
return $op1 / $op2;
}
}
class CMath
{
protected $calc = null;
public function __construct($type)
{
$calc = 'Math' . $type;
$this->calc = new $calc();
}
public function calc($op1, $op2)
{
return $this->calc->calc($op1, $op2);
}
}
$type = 'Add';
$cmath = new CMath($type);
echo $cmath->calc(10, 5);
八、装饰器模式
在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能,它是通过创建一个包装对象,也就是装饰来包裹真实的对象。
<?php
class BaseArt
{
protected $content;
protected $art = null;
public function __construct($content)
{
$this->content = $content;
}
public function decorator()
{
return $this->content;
}
}
//小编类,编辑文章摘要
class BianArt extends BaseArt
{
public function __construct(BaseArt $art)
{
$this->art = $art;
$this->decorator();
}
public function decorator()
{
return $this->content = $this->art->decorator() . '小编加上文章摘要';
}
}
//SEO类,加SEO关键词
class SEOArt extends BaseArt
{
public function __construct(BaseArt $art)
{
$this->art = $art;
$this->decorator();
}
public function decorator()
{
return $this->content = $this->art->decorator() . 'SEO关键字';
}
}
$b = new BianArt(new BaseArt('好好学习'));
echo $b->decorator();
九、适配器模式
将一个类的接口转换成客户希望的另一个接口,适配器模式使得原本由于接口不兼容而不能在一起的那些类可以一起工作
应用场景:老代码接口不适应新的接口需求,或者代码很多很乱不便于继续修改,或者使用第三方类库。
<?php
//服务器端代码
class tianqi
{
public static function show()
{
$today = array('tep' => 28, 'wind' => 7, 'sun' => 'sunny');
return serialize($today);
}
}
//====客户端调用======
$tq = unserialize(tianqi::show());
//来了一批手机上的java客户端,不认识java串行化后的字符串怎么办
//把服务器端代码改了?旧的客户端又会受影响
//增加一个适配器
class AdapterTianqi extends tianqi
{
public static function show()
{
$today = parent::show();
$today = unserialize($today);
$today = json_encode($today);
return $today;
}
}
//java,python 再来调用,通过适配器调用
$tp = AdapterTianqi::show();
print_r(json_decode($tp));
十、桥接模式
桥接模式(Bridge Pattern)是一种结构型设计模式,主要目的是通过分离实现与抽象来让不同的类对同一个抽象有不同的实现。
<?php
abstract class info
{
protected $send = null;
public function __construct($send)
{
$this->send = $send;
}
abstract public function msg($content);
public function send($to, $content)
{
$content = $this->msg($content);
$this->send->send($to, $content);
}
}
class zn
{
public function send($to, $content)
{
echo '站内给' . $to, '内容是' . $content;
}
}
class email
{
public function send($to, $content)
{
echo 'email给' . $to, '内容是' . $content;
}
}
class sms
{
public function send($to, $content)
{
echo 'sms给' . $to, '内容是' . $content;
}
}
class commoninfo extends info
{
public function msg($content)
{
return '普通' . $content;
}
}
class warninfo extends info
{
public function msg($content)
{
return '紧急' . $content;
}
}
class dangerinfo extends info
{
public function msg($content)
{
return '特急' . $content;
}
}
//用站内发普通信息
$commoninfo = new commoninfo(new zn());
$commoninfo->send('小明', '吃饭了');
站内给小明内容是普通吃饭了