Extend/User.php
id = $id;
$this->pdo = new \PDO('mysql:host=127.0.0.1;dbname=test','root','123456');
}
function __destruct()
{
$this->pdo->query("update user set name = '{$this->name}',salary = '{$this->salary}',city = '{$this->city}' where id='{$this->id}'");
}
}
这样,就实现了稍复杂的数据对象映射模式和工厂模式、注册树模式相结合的案例。
4、观察者模式
当一个对象状态发生改变时,依赖它的对象会全部收到通知,并自动更新。
场景:一个事件发生后,要执行一连串更新操作。传统的编程方式就是在事件的代码之后直接加入处理逻辑,当更新的逻辑增多之后,代码会变的难以维护。这种方式是耦合的,侵入式的,增加新的逻辑需要修改事件主体的代码。观察者模式实现了低耦合,非侵入式的通知与更新机制。
4.1、传统模式举例:
";
//传统方式是在发生一个事件之后直接进行一系列的相关处理,耦合度比较高,比如写入日志,给用户发邮件等等
echo "在用户下单之后进行的一系列操作
";
}
}
$event = new Event();
$event->firmOrder();
4.2、观察者模式典型实现方式:
(1)定义2个接口:观察者(通知)接口、被观察者(主题)接口
(2)定义2个类,观察者类实现观察者接口、被观察者类实现被观察者接口
(3)被观察者注册自己需要通知的观察者
(4)被观察者类某个业务逻辑发生时,通知观察者对象,进而每个观察者执行自己的业务逻辑。
代码示例:
test.php
observers[] = $observer;
}
/**
* 购票主体方法
* BuyTicket constructor.
* @param $ticket 购票排号
*/
public function buyTicket($ticket)
{
//1、根据需求写购票逻辑
//..............
//2、购票成功之后,循环通知观察者,并调用其buyTicketOver实现不同业务逻辑
foreach ($this->observers as $observe) {
$observe->buyTicketOver($this, $ticket); //$this 可用来获取主题类句柄,在通知中使用
}
}
}
/**
* 购票成功后,发送短信通知
* Class buyTicketMSN
*/
class buyTicketMSN implements TicketObserver
{
public function buyTicketOver($sender, $ticket)
{
echo (date ( 'Y-m-d H:i:s' ) . " 短信日志记录:购票成功:$ticket
");
}
}
/**
* 购票成功后,记录日志
* Class buyTicketLog
*/
class buyTicketLog implements TicketObserver
{
public function buyTicketOver($sender, $ticket)
{
echo (date ( 'Y-m-d H:i:s' ) . " 文本日志记录:购票成功:$ticket
");
}
}
/**
* 购票成功后,赠送优惠券
* Class buyTicketCoupon
*/
class buyTicketCoupon implements TicketObserver
{
public function buyTicketOver($sender, $ticket)
{
echo (date ( 'Y-m-d H:i:s' ) . " 赠送优惠券:购票成功:$ticket 赠送10元优惠券1张。
");
}
}
//实例化购票类
$buy = new BuyTicket();
//添加多个观察者
$buy->addObserver(new buyTicketMSN());
$buy->addObserver(new buyTicketLog());
$buy->addObserver(new buyTicketCoupon());
//开始购票
$buy->buyTicket ("7排8号");
浏览器显示结果:
5、原型模式
原型模式与工厂模式的作用类似,都是用来创建对象的。但是实现方式是不同的。原型模式是先创建好一个原型对象,然后通过clone原型对象来创建新的对象。这样,就免去了类创建时重复的初始化操作。
原型模式适用于大对象的创建,创建一个大对象需要很大的开销,如果每次new就会消耗很大,原型模式仅需内存拷贝即可。
代码实例:
_name = $name;
}
public function setName($name)
{
$this->_name = $name;
}
public function getName()
{
return $this->_name;
}
public function copy()
{
//深拷贝实现
//$serialize_obj = serialize($this); // 序列化
//$clone_obj = unserialize($serialize_obj); // 反序列化
//return $clone_obj;
// 浅拷贝实现
return clone $this;
}
}
/**
* 测试深拷贝用的引用类
*/
class Demo
{
public $array;
}
//测试
$demo = new Demo();
$demo->array = array(1, 2);
$object1 = new ConcretePrototype($demo);
$object2 = $object1->copy();
var_dump($object1->getName());
echo '
';
var_dump($object2->getName());
echo '
';
$demo->array = array(3, 4);
var_dump($object1->getName());
echo '
';
var_dump($object2->getName());
echo '
';
浏览器显示结果:
6、装饰器模式
可以动态的添加或修改类的功能
一个类实现一个功能,如果要再修改或添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法。
使用装饰器模式,仅需在运行时添加一个装饰器对象即可实现,可以实现最大的灵活性。
color = $color;
}
public function beforeEcho()
{
echo "color}'>";
}
public function afterEcho()
{
echo "";
}
}
/**
* 字体大小装饰器实现
* Class SizeDecorator
*/
class SizeDecorator implements Decorator
{
protected $size;
public function __construct($size)
{
$this->size = $size;
}
public function beforeEcho()
{
echo "size}px'>";
}
public function afterEcho()
{
echo "";
}
}
/**
* 被装饰者
* 输出一个字符串
* 装饰器动态添加功能
* Class EchoText
*/
class EchoText
{
protected $decorators = array();//存放装饰器
//装饰方法
public function Index()
{
//调用装饰器前置操作
$this->beforeEcho();
echo "你好,我是装饰器。";
//调用装饰器后置操作
$this->afterEcho();
}
//添加装饰器
public function addDecorator(Decorator $decorator)
{
$this->decorators[] = $decorator;
}
//执行装饰器前置操作 先进先出原则
protected function beforeEcho()
{
foreach ($this->decorators as $decorator)
$decorator->beforeEcho();
}
//执行装饰器后置操作 先进后出原则
protected function afterEcho()
{
$tmp = array_reverse($this->decorators);
foreach ($tmp as $decorator)
$decorator->afterEcho();
}
}
//实例化输出类
$echo = new EchoText();
//增加装饰器
$echo->addDecorator(new ColorDecorator('yellow'));
//增加装饰器
$echo->addDecorator(new SizeDecorator('22'));
//输出
$echo->Index();
7、迭代器模式
在不需要了解内部实现的前提下,遍历一个聚合对象的内部元素而又不暴露该对象的内部表示,这就是PHP迭代器模式的定义。
相对于传统编程模式,迭代器模式可以隐藏遍历元素的所需的操作。
index.php
Extend/AllUser.php
pdo = new \PDO('mysql:host=127.0.0.1;dbname=test','root','123456');
//获取所有用户的id
$this->ids = $this->pdo->query("select id from user")->fetchAll(2);
}
/**
* 实现接口方法,重置迭代器,回到集合开头
*/
public function rewind()
{
$this->index = 0;
}
/**
* 实现接口方法,获取当前元素
* @return mixed|void
*/
public function current()
{
$id = $this->ids[$this->index]['id'];
//获取当前用户的数据
$user_data = $this->pdo->query("select * from user where id='{$id}'")->fetch(2);
return $user_data;
}
/**
* 实现接口方法,获取当前元素键值
* @return mixed|void
*/
public function key()
{
return $this->index;
}
/**
* 实现接口方法,获取下一个元素
*/
public function next()
{
$this->index++;
}
/**
* 实现接口方法,验证是否还有下一个元素
* @return bool|void
*/
public function valid()
{
return $this->index < count($this->ids);
}
}
8、代理模式
在客户端与实体之间建立一个代理对象(proxy),客户端对实体进行操作全部委派给代理对象,隐藏实体的具体实现细节。
典型的应用就是mysql的主从结构,读写分离。在mysql中,对所有读的操作请求从库,所有写的操作请求主库。
声明一个代理类,前台使用时只需创建一个代理类,调用对应方法即可。代码实例:
index.php
query("select * from user where id = 1 limit 1");
#增删改操作使用主库
//$db_master = Extend\Factory::getDatabase('master');
//$db_master->query("update user name = 'xiaobudiu' where id = 29 limit 1");
// 2、使用代理模式
$db_proxy = new Extend\Proxy();
$db_proxy->getUserName(1);
$db_proxy->setUserName(29,'xiaobudiu');
Extend/Proxy.php
query("select name from user where id =$id limit 1");
}
function setUserName($id, $name)
{
$db = Factory::getDatabase('master');
$db->query("update user set name = $name where id =$id limit 1");
}
}
Extend/Factory.php
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;
}
}
Extend/Application.php
base_dir = $base_dir;
$this->config = new Config($base_dir.'/configs');
}
static function getInstance($base_dir = '')
{
if (empty(self::$instance))
{
self::$instance = new self($base_dir);
}
return self::$instance;
}
}
Extend/Config.php
path = $path;
}
function offsetGet($key)
{
if (empty($this->configs[$key]))
{
$file_path = $this->path.'/'.$key.'.php';
$config = require $file_path;
$this->configs[$key] = $config;
}
return $this->configs[$key];
}
function offsetSet($key, $value)
{
throw new \Exception("cannot write config file.");
}
function offsetExists($key)
{
return isset($this->configs[$key]);
}
function offsetUnset($key)
{
unset($this->configs[$key]);
}
}
configs/database.php
array(
'type' => 'MySQL',
'host' => '127.0.0.1',
'user' => 'root',
'password' => '123456',
'dbname' => 'test',
),
'slave' => array(
'slave1' => array(
'type' => 'MySQL',
'host' => '127.0.0.1',
'user' => 'root',
'password' => '123456',
'dbname' => 'test',
),
'slave2' => array(
'type' => 'MySQL',
'host' => '127.0.0.1',
'user' => 'root',
'password' => '123456',
'dbname' => 'test',
),
),
);
return $config;
五、其余设计模式以及总结
六、面向对象编程的基本原则
1、单一职责原则:一个类只需要做好一件事情。不要使用一个类完成很多功能,而应该拆分成更多更小的类。
2、开放封闭原则:一个类写好之后,应该是可扩展而不可修改的。
3、依赖倒置原则:一个类不应该强依赖另外一个类,每个类对于另外一个类都是可替换的。
4、配置化原则:尽量使用配置,而不是硬编码。
5、面向接口编程原则:只需要关心某个类提供了哪些接口,而不需要关心他的实现。
七、自动加载配置类文件
1、php中使用ArrayAccess实现配置文件的加载(使得程序可以以数组的方式进行读取配置)
(1)定义Config.php,继承php自带的ArrayAccess接口,并实现相应的方法,用于读取和设置配置
Extend/Config.php
path = $path;
}
function offsetGet($key)
{
if (empty($this->configs[$key]))
{
$file_path = $this->path.'/'.$key.'.php';
$config = require $file_path;
$this->configs[$key] = $config;
}
return $this->configs[$key];
}
function offsetSet($key, $value)
{
throw new \Exception("cannot write config file.");
}
function offsetExists($key)
{
return isset($this->configs[$key]);
}
function offsetUnset($key)
{
unset($this->configs[$key]);
}
}
(2)configs/database.php
array(
'type' => 'MySQL',
'host' => '127.0.0.1',
'user' => 'root',
'password' => '123456',
'dbname' => 'test',
),
'slave' => array(
'slave1' => array(
'type' => 'MySQL',
'host' => '127.0.0.1',
'user' => 'root',
'password' => '123456',
'dbname' => 'test',
),
'slave2' => array(
'type' => 'MySQL',
'host' => '127.0.0.1',
'user' => 'root',
'password' => '123456',
'dbname' => 'test',
),
),
);
return $config;
(3)读取配置
index.php
(4)浏览器显示:
到此,就可以在程序中随心所欲的加载配置文件了。
2、在工厂方法中读取配置,生成可配置化的对象
Extend/Factory.php
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;
}
}
Extend/Application.php
base_dir = $base_dir;
$this->config = new Config($base_dir.'/configs');
}
static function getInstance($base_dir = '')
{
if (empty(self::$instance))
{
self::$instance = new self($base_dir);
}
return self::$instance;
}
}
Extend/Config.php
path = $path;
}
function offsetGet($key)
{
if (empty($this->configs[$key]))
{
$file_path = $this->path.'/'.$key.'.php';
$config = require $file_path;
$this->configs[$key] = $config;
}
return $this->configs[$key];
}
function offsetSet($key, $value)
{
throw new \Exception("cannot write config file.");
}
function offsetExists($key)
{
return isset($this->configs[$key]);
}
function offsetUnset($key)
{
unset($this->configs[$key]);
}
}
以上就是PHP开发自己的框架,你必须知道这些知识点!的详细内容,更多请关注 模板之家(www.mb5.com.cn) 其它相关文章!