注册器(树)模式:用来将对象注册到全局的树上面,在哪里都能访问
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
namespace DuiCode; class Register{ protected $objects; //将类映射注册到全局树上 /** * @param $alias 别名 * @param $object 对象 */ static function set($alias, $object){ self::$objects[$alias] = $object; } //获取注册的对象 static function get($name){ return self::$objects[$name]; } function _unset($alias){ unset(self::$objects[$alias]); } } |
工厂模式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
namespace DuiCode; use DuiCode\Database\MySQLi; class Factory{ static function createDatabase(){ $db = Database::getInstance(); return $db; } static $proxy = null; /** * @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; } /** * @param $name * @return bool */ static function getModel($name) { $key = 'app_model_'.$name; $model = Register::get($key); if (!$model) { $class = '\\App\\Model\\'.ucwords($name); $model = new $class; Register::set($key, $model); } return $model; } static function getDatabase($id = 'proxy') { if ($id == 'proxy') { if (!self::$proxy) { self::$proxy = new \DuiCode\Database\Proxy; } return self::$proxy; } $key = 'database_'.$id; if ($id == 'slave') { $slaves = Application::getInstance()->config['database']['slave']; $db_conf = $slaves[array_rand($slaves)]; } else { $db_conf = Application::getInstance()->config['database'][$id]; } $db = Register::get($key); if (!$db) { $db = new Database\MySQLi(); $db->connect($db_conf['host'], $db_conf['user'], $db_conf['password'], $db_conf['dbname']); Register::set($key, $db); } return $db; } } |
适配器模式:将截然不同的函数接口封装成统一的API
举例:mysql,mysqli,pdo三种数据库操作可以用适配器模式统一成一致,还有将 memcache、redis、file、apc等不同的缓存函数,统一成一致
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
interface IDatabase{ function connect($host, $user, $passwd, $dbname); function query($sql); function close(); } //PHP中链式操作的实现 class Database{ protected $db; /**!!!!!单例模式!!!!!!!**/ //构造方法私有化 private function __construct(){ } //获取实例 static function getInstance(){ if (self::$db){ return self::$db; }else { self::$db = new self(); return self::$db; } } function where($where){ //这一句就是为了实现链式操作 return $this; } function order($order){ return $this; } function limit($limit){ return $this; } } class MySQL implements IDatabase{ protected $conn; function connect($host, $user, $passwd, $dbname){ // TODO: Implement connect() method. $conn = mysql_connect($host, $user, $passwd); mysql_select_db($dbname,$conn); $this->conn = $conn; } function query($sql){ // TODO: Implement query() method. $res = mysql_query($sql,$this->conn); return $res; } function close(){ // TODO: Implement close() method. mysql_close($this->conn); } } |
策略模式:将一组特定的行为和算法封装成类,以适应某些特定的上下文环境,这种模式就是策略模式,
比如一个电商网站,针对男女用户要各自跳转到不同的商品类目,并且所有广告位展示不同广告。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
namespace DuiCode; interface UserStrategy{ function showAd(); function showCategory(); } namespace DuiCode; class FemaleUserStrategy implements UserStrategy{ function showAd(){ // TODO: Implement showAd() method. echo "新款女装"; } function showCategory(){ // TODO: Implement showCategory() method. echo "女装"; } } class Page{ protected $strategy; function index(){ echo "AD:"; $this->strategy->showAd(); echo "<br />"; echo "Category:"; $this->strategy->showCategory(); echo "<br />"; } function setStrategy(\DuiCode\UserStrategy $strategy){ $this->strategy = $strategy; } } $page = new Page; if (isset($_GET['female'])){ $strategy = new \DuiCode\FemaleUserStrategy(); }else{ $strategy = new \DuiCode\MaleUserStrategy(); } $page->setStrategy($strategy); |
数据对象映射模式,是将对象和数据存储映射起来,对一个对象的操作会映射为对数据存储的操作,比如ORM类,将复杂的SQL语句映射成对象属性的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
namespace DuiCode; class User{ public $id; public $name; public $mobile; public $regtime; protected $db; function __construct($id){ $this->db = new \DuiCode\Database\MySQLi(); $this->db->connect('127.0.01','root','root','test'); $res = $this->db->query("SELECT * FROM user LIMIT 1;"); $data = $res->fetch_assoc(); $this->id = $data['id']; $this->name=$data['name']; $this->mobile=$data['mobile']; $this->regtime=$data['regtime']; } function __destruct(){ // TODO: Implement __destruct() method. $this->db->query("UPDATE user SET name = '{$this->name}',mobile='{$this->mobile}',regtime='{$this->regtime}' WHERE id = {$this->id} LIMIT 1;"); } } |
观察者模式:当一个对象状态发生改变时,依赖它的对象全部会受到通知,并自动更新。观察者模式实现了低耦合,非侵入式的通知与更新机制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
namespace DuiCode; interface Observer{ function update($event_info = null); } namespace DuiCode; abstract class EventGenerator{ private $observers = array(); function addObserver(Observer $observer){ $this->observers[] = $observer; } function notify(){ foreach ($this->observers as $observer){ $observer->update(); } } } class Event extends \DuiCode\EventGenerator{ function trigger(){ echo "Event<br/>\n"; /**传统模式update echo "逻辑1<br/>\n"; echo "逻辑2<br/>\n"; echo "逻辑3<br/>\n"; **/ //发送通知 $this->notify(); } } |
原型模式:与工厂模式类似,都是用来创建对象,与工厂模式的实现不同,原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样就免去了类创建时重复的初始化操作。原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
//原型模式 $prototype = new \DuiCode\Canvas(); $prototype->init(); $canvas3 = clone $prototype; $canvas3->init(); $canvas3->rect(3, 6, 4, 12); $canvas3->draw(); echo '<hr /><br />\n'; $canvas4 = clone $prototype; $canvas4->init(); $canvas4->rect(1, 3, 2, 6); $canvas4->draw(); |
装饰器模式:可以动态地添加修改类的功能。一个类提供了一项功能,如果在修改并添加额外的功能,传统的编程模式,需要写一个子类继承它,并重新实现类的方法。使用装饰器模式,仅需在运行时添加一个装饰器对象,即可实现,可以实现最大的灵活性。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
namespace DuiCode; interface DrawDecorator{ function beforeDraw(); function afterDraw(); } namespace DuiCode; class ColorDrawDecorator implements DrawDecorator{ protected $color; function __construct($color = 'red'){ $this->color = $color; } function beforeDraw(){ // TODO: Implement beforeDraw() method. echo "<div style='color: {$this->color}'>"; } function afterDraw(){ // TODO: Implement afterDraw() method. echo "</div>"; } } namespace DuiCode; class SizeDrawDecorator implements DrawDecorator{ protected $size; function __construct($size = '14px'){ $this->size = $size; } function beforeDraw(){ // TODO: Implement beforeDraw() method. echo "<div style='font-size: {$this->size}'>"; } function afterDraw(){ // TODO: Implement afterDraw() method. echo "</div>"; } } namespace DuiCode; class Canvas{ public $data; protected $decorators = array(); 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); foreach ($decorators as $decorator) { $decorator->afterDraw(); } } function draw(){ $this->beforeDraw(); foreach ($this->data as $line){ foreach ($line as $char){ echo $char; } echo "<br />\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] = ' '; } } } } |
迭代器模式:在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素。相对于传统的编程模式,迭代器模式可以隐藏遍历元素所需的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
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); } //获取当前的元素(第三个调用) function current(){ // TODO: Implement current() method. $id = $this->ids[$this->index]['id']; return Factory::getUser($id); } //下一个元素(第四步) function next(){ // TODO: Implement next() method. $this->index ++; } //验证当前是否还有下一个元素(第二个调用) function valid(){ // TODO: Implement valid() method. return $this->index < count($this->ids); } //重置整个迭代器 function rewind(){ // TODO: Implement rewind() method. return $this->index; } //在迭代器中的位置(第一个调用) function key(){ // TODO: Implement key() method. $this->index = 0; } } |
代理模式:在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节。Proxy还可以与业务代码分离,部署到另外的服务器,业务代码通过RPC来委派任务。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
namespace DuiCode; interface IUserProxy{ function getUserName($id); function setUserName($id, $name); } namespace DuiCode; class Proxy implements IUserProxy{ function getUserName($id){ // TODO: Implement getUserName() method. //这里写数据库操作 } function setUserName($id, $name){ // TODO: Implement setUserName() method. //这里写数据库操作 } } |
下面介绍一下PHP中封装好的一些数据结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
//SPL常用数据结构的使用 //栈 先进后出 $stack = new SplStack(); $stack->push("打他"); //入栈 $stack->pop(); //出栈 //队列 先进先出 $queue = new SplQueue(); $queue->enqueue("揍他"); //入队列 $queue->dequeue(); //出队列 //堆 //最小堆 $heap = new SplMinHeap(); $heap->insert("夯他"); //插入 $heap->extract(); //提取 //固定长度的数组 $array = new SplFixedArray(10); $array[0] = 123; $array[9] = 1234; |
PHP魔术方法大致分成四类:
1、__set/__get,修改对象不存在的属性和获取对象不存在的属性;
2、__toString();将一个对象当成一个字符串打印的时候调用;
3、__call/__callStatic:调用一个不存在的方法或者一个不存在的静态方法的时候调用;
4、__invoke,将对象当成函数调用的时候该魔术方法被调
面向对象的基本原则:
1.单一职责:一个类,只需要做好一件事情。
2.开放封闭:一个类应该是可扩展的,而不可修改的。
3.依赖倒置:一个类,不应该强依赖另外一个类。每个类对于另外一个类都是可替代的。
4.配置化:尽可能地使用配置,而不是硬编码。
5.面向接口编程:只需要关心接口,不需要关心实现。
配置与设计模式
1.PHP中使用ArrayAccess实现配置文件的加载
2.在工厂方法中读取配置,生成可配置化得对象
3.使用装饰器模式实现权限验证,模板渲染,JSON串化
4.使用观察者模式实现数据更新事件的一系列更新操作
5.使用代理模式实现数据库的主从自动切换
更多源码请查LearningPHP
转载请注明:怼码人生 » PHP中常用的设计模式