# designMode **Repository Path**: xihafugui/designMode ## Basic Information - **Project Name**: designMode - **Description**: No description available - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2018-09-28 - **Last Updated**: 2020-12-18 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # PHP设计模式 学习实践 目录 1、命名空间 2、类自动载入 3、PSR-0基础框架 4、SPL标准库 5、链式操作* 6、魔术方法的使用* 7、基础设计模式简介 8、工厂模式* 9、单例模式* 10、注册模式 11、适配器模式 12、策略模式 13、数据对象映射模式* 14、观察者模式 15、原型模式 16、装饰器模式* 17、迭代器模式* 18、代理模式 ### PSR-0 1、PHP的命名空间必须与绝对路径一致 2、类名的首字母必须大写 3、除了入口文件为,其他的".php"文件必须只有一个类 ### 开发符合PSR-0规范的基础框架 1、全部使用命名空间 2、所有PHP文件必须自动载入,不能有include/require 3、单一入口 ### SPL库的使用(PHP 标准库) 1、SplStack、SplQueue、SplHeap、SplFixedArray等数据结构类 2、ArrayIterator、AppendIterator、Countable、ArrayObject 3、SPL提供的函数 ```$xslt /* * 栈结构、先进后出 */ $stack = new SplStack(); $stack->push("data1\n");//入栈 $stack->push("data2\n");//入栈 echo $stack->pop(); echo $stack->pop(); /* * 队列结构、先进先出 */ $queue = new SplQueue(); $queue->enqueue("data_q1"); $queue->enqueue("data_q2"); echo $queue->dequeue(); echo $queue->dequeue(); /* * 堆结构、先进先出 */ $heap = new SplMinHeap();//最小堆 $heap->insert("data_h1"); $heap->insert("data_h2"); echo $heap->extract(); echo $heap->extract(); /* * 固定长度数组 */ $heap_array = new SplFixedArray(10); $heap_array[0] = 123; $heap_array[9] = 321; var_dump($heap_array); ``` ### 链式操作 原理:返回 `$this` ```$xslt class Database { function where($where) { return $this; } function order($order) { return $this; } function limit($limit) { return $this; } } $db = new \Imooc\Database(); $db->where("id=1")->where("name=2")->limit("1")->order("id desc"); ``` ### PHP魔术方法的使用 ``` 1. __get/__set //接管 类的属性 2. __call/__callStatic //控制PHP对象对方法的调用 3. __toString //将对象转换成字符串 4. __invoke //将PHP对象当初函数执行 ``` ```$xslt function __set($name, $value) { var_dump(__METHOD__); $this->array[$name] = $value; } function __get($name) { var_dump(__METHOD__); return $this->array[$name]; } function __call($name, $arguments) { var_dump($name, $arguments); return "magic function\n"; } function __toString() { return __CLASS__; } function __invoke() { return "invoke2"; } ``` ### 工厂模式 ***工厂方法或者类生成对象,而不是在代码中直接new*** ***好处:如果类有修改,比如修改类名,则只需要修改一处*** ```$xslt class Factory { static function createDatabase() { $db = new Database(); return $db; } } $db = \Imooc\Factory::createDatabase(); ``` ### 单例模式 ***使某个类的对象仅允许创建一个*** ```$xslt class Database { protected static $db; //屏蔽构造函数,在其他地方不允许 实例化 private function __construct() { } //获取实例 static function getInstance() { if (self::$db){ return self::$db; }else{ self::$db = new self(); return self::$db; } } } class Factory { static function createDatabase() { $db = Database::getInstance();//此处无法 new Database(); 只能静态调用getInstance() return $db; } } $db = \Imooc\Factory::createDatabase(); ``` ### 注册模式 ***全局共享和交换对象*** ```$xslt class Register { protected static $objects; static function set($alias,$object) { self::$objects[$alias] = $object; } static function get($name) { return self::$objects[$name]; } static function _unset($alias) { unset(self::$objects[$alias]); } } class Factory { static function createDatabase() { $db = Database::getInstance(); Register::set("db1",$db);//将变量注册,赋予别名 return $db; } } $db = \Imooc\Factory::createDatabase(); $db1 = \Imooc\Register::get('db1');//注册之后,直接获取别名也可以使用对象 ``` ### 适配器模式 ***可以将 截然不同的函数接口封装成统一的API*** ```$xslt //实现统一接口 interface IDatabase { function connect($host, $user, $passwd, $dbname); function query($sql); function close(); } //分不同场景实现接口方法 class MySQL implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $conn = mysql_connect($host, $user, $passwd, $dbname); mysql_select_db($dbname,$conn); $this->conn = $conn; } function query($sql) { $res = mysql_query($sql, $this->conn); return $res; } function close() { mysql_close($this->conn); } } class MySQLi implements IDatabase { function connect($host, $user, $passwd, $dbname) { // TODO: Implement connect() method. } function query($sql) { // TODO: Implement query() method. } function close() { // TODO: Implement close() method. } } class PDO implements IDatabase { protected $conn; function connect($host, $user, $passwd, $dbname) { $this->conn = new \PDO("mysql:host=$host;dbname=$dbname", $user, $passwd); } function query($sql) { $this->conn->query($sql); } function close() { unset($this->conn); } } $db = new Imooc\Database\MySQL();//此处可以替换成MySQLi()或PDO(),下面的接口方法和参数都不会变,适配器实现 $db->connect('127.0.0.1','root','','test'); $db->query(); $db->close(); ``` ### 策略模式 ***将一组特定的行为和算法封装成类,以适应某些特定的上下文环境*** ***栗子:一个电商网站系统,针对男性、女性用户要个子跳转到不同的商品类目,并且展示不同的广告*** ```$xslt //封装特定行为接口 interface UserStrategy { function showAd(); function showCategory(); } //实现不同的策略 class FemaleUserStrategy implements UserStrategy { function showAd() { echo '2018女装'; } function showCategory() { echo '女装'; } } class MaleUserStrategy implements UserStrategy { function showAd() { echo '2018新手机'; } function showCategory() { echo '男装'; } } //使用策略模式 class Page { /** * @var \Imooc\UserStrategy */ protected $strategy; function index() { $this->strategy->showAd(); $this->strategy->showCategory(); } function setStrategy(\Imooc\UserStrategy $strategy) { $this->strategy = $strategy; } } $page = new Page(); //根据不同的上下文,设置不同的策略 if (isset($_GET['female'])){ $strategy = new \Imooc\FemaleUserStrategy(); }else{ $strategy = new \Imooc\MaleUserStrategy(); } //将对象保存在成员变量 $page->setStrategy($strategy); $page->index(); ``` ### 策略模式的控制反转 ***使用策略模式可以实现Ioc,依赖倒置、控制反转*** ### 数据对象映射模式 ***将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作*** ***复杂实现,使用数据对象映射模式、工厂模式、注册器模式*** ``` class Page { function index() { $user = \Imooc\Factory::getUser(1);//工厂 $user->name = 'test1'; $this->test(); } function test() { $user = \Imooc\Factory::getUser(1);//工厂 $user->mobile = '18900001111'; } } $page = new Page(); $page->index(); class Factory { /** * @param $id * @return User */ static function getUser( $id ) { $key = 'user_'.$id; $user = Register::get($key);//注册器 if (!$user){ $user = new User($id); Register::set($key , $user);//注册器 } return $user; } } //数据对象映射 class User { public $id; public $name; public $mobile; public $regtime; protected $db; function __construct($id) { $this->db = new MySQLi();//此处可以替换成MySQLi()或PDO(),下面的接口方法和参数都不会变,适配器实现 $this->db->connect('127.0.0.1','root','','test'); $res = $this->db->query('select * from user limit 1'); $data = $res->fetch_assoc(); } function __destruct() { $this->db->close(); } } ``` ### 观察者模式 ***当一个对象状态发生改变时,依赖它的对象全部会收到通知,并自动更新*** ***低耦合,非侵入式的通知与更新机制*** ``` /** * 事件产生者 * Class EventGenerator * @package Imooc */ abstract class EventGenerator { private $observers = []; function addObserver(Observer $observer) { $this->observers[] = $observer; } function notify() { foreach ($this->observers as $observer){ $observer->update(); } } } /** * 事件观察者接口 * Interface Observer * @package Imooc */ interface Observer { function update($event_info = null); } /** * 使用观察者模式 */ class Event extends \Imooc\EventGenerator { function trigger() { echo "Event
\n"; $this->notify(); } } class Observer1 implements \Imooc\Observer { function update($event_info = null) { echo "逻辑1
\n"; } } class Observer2 implements \Imooc\Observer { function update($event_info = null) { echo "逻辑2
\n"; } } $event = new Event(); $event->addObserver(new Observer1());//添加观察者 $event->addObserver(new Observer2());//添加观察者 $event->trigger(); ``` ### 原型模式 ***与工厂模式作用类似,都是用来创建对象*** ***与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象类创建新的对象。这样就免去了类创建时重复的初始化操作*** ***原型模式适用于大对象的创建。没创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可*** ``` //大对象 class Canvas { public $data; function init($width = 20, $height = 10) { $data = array(); for($i = 0; $i < $height; $i++) { for($j = 0; $j < $width; $j++) { $data[$i][$j] = '*'; } } $this->data = $data; } function draw() { foreach($this->data as $line) { foreach($line as $char) { echo $char; } echo "
\n"; } } function rect($a1, $a2, $b1, $b2) { foreach($this->data as $k1 => $line) { if ($k1 < $a1 or $k1 > $a2) continue; foreach($line as $k2 => $char) { if ($k2 < $b1 or $k2 > $b2) continue; $this->data[$k1][$k2] = ' '; } } } } //实现原型模式 $prototype = new \Imooc\Canvas();//创建原型对象 $prototype->init();//利用原型对象进行初始化操作 $canvas1 = clone $prototype;//克隆原型对象 $canvas1->rect(3,6,4,12); $canvas1->draw(); echo '=============================
'; $canvas2 = clone $prototype;//克隆原型对象 $canvas2->rect(1,3,2,6); $canvas2->draw(); ``` ### 装饰器模式 ***装饰器模式(Decorator),可以动态添加修改类的功能*** ***一个类提供了一项功能,如果要在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法*** ***使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性*** ``` interface DrawDecorator { function beforeDraw(); function afterDraw(); } class Canvas { public $data; protected $decorators = array(); //Decorator function init($width = 20, $height = 10) { $data = array(); for($i = 0; $i < $height; $i++) { for($j = 0; $j < $width; $j++) { $data[$i][$j] = '*'; } } $this->data = $data; } function addDecorator(DrawDecorator $decorator)//添加装饰器 { $this->decorators[] = $decorator; } function beforeDraw() { foreach($this->decorators as $decorator)//动态添加 { $decorator->beforeDraw(); } } function afterDraw() { $decorators = array_reverse($this->decorators);//after 后进先出 foreach($decorators as $decorator)//动态添加 { $decorator->afterDraw(); } } function draw() { $this->beforeDraw(); foreach($this->data as $line) { foreach($line as $char) { echo $char; } echo "
\n"; } $this->afterDraw(); } function rect($a1, $a2, $b1, $b2) { foreach($this->data as $k1 => $line) { if ($k1 < $a1 or $k1 > $a2) continue; foreach($line as $k2 => $char) { if ($k2 < $b1 or $k2 > $b2) continue; $this->data[$k1][$k2] = ' '; } } } } //颜色装饰器 class ColorDrawDecorator implements DrawDecorator { protected $color; function __construct($color = 'red') { $this->color = $color; } function beforeDraw() { echo "
"; } function afterDraw() { echo "
"; } } //字体大小装饰器 class SizeDrawDecorator implements DrawDecorator { protected $size; function __construct($size = '14px') { $this->size = $size; } function beforeDraw() { echo "
"; } function afterDraw() { echo "
"; } } $canvas1 = new \Imooc\Canvas(); $canvas1->init(); $canvas1->addDecorator(new \Imooc\ColorDrawDecorator('blue'));//添加颜色装饰器 $canvas1->addDecorator(new \Imooc\SizeDrawDecorator('32'));//添加字体大小装饰器 $canvas1->rect(3,6,4,12); $canvas1->draw(); ``` ### 迭代器模式 ***在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素*** ***相比于传统的编程模式,迭代器可以隐藏遍历元素的所需操作*** ***需要实现SPL 的Iterator接口*** ``` class AllUser implements \Iterator { protected $ids; protected $data = array(); protected $index; function __construct() { $db = Factory::getDatabase(); $result = $db->query("select id from user"); $this->ids = $result->fetch_all(MYSQLI_ASSOC); } /** * @1st */ public function rewind() { $this->index = 0; } /** * @2nd * @return bool */ public function valid() { return $this->index < count($this->ids) ; } /** * @3rd * @return User|mixed */ public function current() { $id = $this->ids[$this->index]['id']; return Factory::getUser($id); } /** * @4th */ public function next() { $this->index++; } /** * @5th * @return mixed */ public function key() { return $this->index; } } //使用 $users = new \Imooc\AllUser(); foreach ($users as $user){ var_dump($user); } ``` ### 代理模式 ***在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行的操作全部委派给代理对象,隐藏实体的具体实现细节*** ***Proxy还可以与业务代码分离,部署到另外的服务器。业务代码中通过RPC来委派任务*** ``` class Proxy implements IUserProxy { function getUserName($id) { $db = Factory::getDatabase('slave'); $db->query("select ..."); } function setUserName($id, $name) { $db = Factory::getDatabase('master'); $db->query("update ..."); } } $proxy = new \Imooc\Proxy(); $proxy->getUserName($id); $proxy->setUserName($id,$name); ``` ### 面向对象编程的基本原则 ***1、单一职责:一个类,只需要做好一件事情。*** ***2、开放封闭:一个类,应该是可扩展的,而不可修改的。*** ***3、依赖倒置:一个类,不应该强依赖另外一个类,每个类对于另外一个类都是可替换的。*** ***4、配置化:尽可能地使用配置,而不是硬编码。*** ***5、面向接口编程:只需要关心接口,不需要关心实现。*** ### MVC ***模型-视图-控制器,一种C/S或者B/S软件工程的组织方式*** >模型(Model):数据和存储的封装 >视图(View):展现层的封装,如Web系统中的模板文件 >控制器(Controller):逻辑层的封装