《PHP设计模式及在框架设计中的经典应用.ppt》由会员分享,可在线阅读,更多相关《PHP设计模式及在框架设计中的经典应用.ppt(32页珍藏版)》请在三一办公上搜索。
1、PHP设计模式及在框架设计中的经典应用,目标,了解设计模式与框架给出一个可行的学习设计模式的方法介绍几种常见的设计模式,Agenda,设计模式简述框架简述设计模式与框架软件开发演进过程框架要解决的问题FactorySingletonRegisterAdapterProxyActive RecordMVC,什么是模式?,demofor(int i=0;i100;i+)主谓宾我爱你计算机领域:在特定场景下、解决某一类问题的通用方法模式分类(参见:POSA-1)架构模式设计模式惯用法,为什么要关注设计模式?,向专家学习向历史学习大型软件设计、实施必备沟通交流的语言薪水+,模式四要素,模式名称(pat
2、tern name)交流、标记问题(problem)场景、上下文解决方案(solution)解决方法、方案效果(consequences)模式应用的效果及使用模式应权衡的问题,框架是什么?,可复用的面向对象软件系统应用程序工具箱api,函数框架(Framework)框架解决特定领域里面具有类似问题的一组相互协作的类提供解决常见问题的通用组件为了“复用”已有的解决方案为了生产效率和可维护性,软件开发演进过程,机器语言、汇编语言高级语言,面向过程编程OOP、设计模式、元编程框架、DSL智能组件?只描述需求、软件就给您实现了?:)程序员担当“智能”,设计自己的框架可能面临的问题,创建大量的复杂对象比
3、较耗资源的对象只希望初始化一次动态处理大量的配置适应不同的数据库希望延迟初始化数据库连接日志处理性能监控.,Warning:接下来的代码供示例使用,不具备产品级可用性,场景一,需要在很多函数中调用数据库的操作假设对数据库的操作已经封装在一个类里面实现 v0可以在函数里面调用该类function foo()$db=new Driver_DB_Mysql();function bar()$db=new Driver_DB_Mysql();问题如果Driver_DB_Mysql(改名了呢?参数变化了呢?,模式一:Factory,工厂模式V0.1Implclass DB_Factory public
4、static function getInstance()$db=new Driver_DB_Mysql()()return$db;使用function foo()$db=DB_Factory:getInstance()使用一致的、简单的方式来初始化复杂的对象,场景二,在一个业务流程中要访问数据库资源,发现多次连接数据库,消耗资源。希望只连接接数据库一次实现v0全局变量中初始化连接$db=Db_Factory:getInstance()业务访问全局变量function foo()global$db;问题bad smells?,模式二:singleton,单例模式+工厂模式Implclass D
5、B_Factory private static$_db;private function _clone();private function _construct()public static function getInstance()if(!(self:$_db instanceof Driver_DB_Mysql)self:$_db=new Driver_DB_Mysql();return self:$_db;使用function foo()$db=DB_Factory:getInstance();实例化一个对象、共享连接,场景三,框架中需要保存一些全局的设置或类的实例,保存框架上下文
6、实现v0使用系统$GLOBALS$GLOBALSdebug=xxx;使用function foo()if($GLOBALSdebug).问题bad smells违反职责SRP,模式三:Registry,Registry+FactoryImplclass Registry private static$_instance;/private static$_data=array();private$_data=array();/感谢一位同学指出。用实例变量还是静态变量,依赖于整体的设计。需要对应修改set,get方法.public static function getInstance().ret
7、urn self:$_instance;.public function set($key,$value)$this-_data$key=$value;public function get($key)return isset($this-_data$key)?$this-_data$key:null;使用$ctx=Reistry:getInstance();$ctx-set(xxxx,oooo)$value=$ctx-get(xxxx)使用单实例的全局对象来代替全局的变量,模式三:Registry+Factory(续),保存读写分离的两个mysql连接保存$ctx=Registry:getI
8、nstance();$ctx-set(db_read)=Db_Factory:getInstance(db_read)$ctx-set(db_write)=Db_Factory:getInstance(db_read)使用$dbReadObj=$ctx-get(db_read)$dbWriteObj=$ctx-get(db_write),场景四,需要同时支持mysql和postgresql连接实现针对每个数据库,单独写一个驱动实例Db_Factory:getMysqlDB()Db_Factory:getPostgresqlDB()问题如何保持不同DB接口的一致性?,模式四:Adapter Pa
9、ttern,定义接口interface IDB public function connect();public function error();public function errno();public static function escape_string($string);public function query($query);public function fetchArray($result);public function fetchRow($result);public function fetchAssoc($result);public function fetc
10、hObject($result);public function numRows($result);public function close();./接口定义供示例用,模式四:Adapter Pattern(续),针对不同的DB实现Driver_DB_Mysql implements IDB private$link;public function connect($server=,$username=,$password=,$new_link=true,$client_flags=0)$this-link=mysql_connect($server,$username,$password,
11、$new_link,$client_flags);public function errno()return mysql_errno($this-link);/.,模式四:Adapter Pattern(续),Adpater+Factory实现DB_Factory public static function getInstance($adapter=Mysql)/参数化工厂 if(!isset(self:$_db$adapter)|($_db$adapter instanceof IDB)if(include_once Drivers/DB/.$type.php)$classname=Dri
12、ver_DB_.ucfirst($type);self:$_db$adapter=new$classname;else throw new Exception(Driver not found);return self:$_db$adapter;使用DB_Factory:getInstance(mysql),场景五,需要延迟初始化一些资源class UserController private$db;/构造函数中初始化资源function _construct()$this-db=DB_Factory:getInstance(mysql)public function manages()$sq
13、l=select*from managers;$users=$tthis-db-getResults($sql);public function foo()echo haha问题foo()方法不需要DB连接,在构造函数里面去连接数据库是不是额外消耗连接资源?,模式五:Proxy,代理模式v1实现共同的接口class Proxy_DB_Mysql implements IDB private$db;public function query($query)if(!$this-db)$this-db=DB_Factory:getInstance(mysql)return$this-db-query
14、($query);.延迟初始化、把耗费资源的操作延迟到必须的时候问题每个方法都需重写一次?,Proxy,代理模式v2使用magic方法class Proxy_DB_Mysql private$mysql;public function _call($method,$args)if(!$this-mysql)$this-mysql=DB_Factory:getInstance(mysql)retrun call_user_func_array(array($this-mysql,$method),$args);使用:function foo()$this-proxy-query($sql);v1
15、 和v2这两种方式哪一个更好呢?,场景六,每次我们都需要原生的sql?function foo()$sql=select*from users;我希望OO,不要有那么多SQL我不懂SQLhow to?nosql:),模式六:Active Record,使用示例$User=new User();$User-name=hanyh;$User-address=北京;$User-save();or$data=array(name=hanyh,address=beijing);$User-save($data);,Active Record,实现class User extend ActiveBase
16、CONST INSERT_SQL=insert into user(name,address)values(?,?);private$data;protected$fields=array(name,address);public function save($data=array()if(empty($data)$this-db-save(SELF:INSERT_SQL,$this-data);else$this-db-save(SELF:INSERT_SQL,$data);private function _set($field,$value)if(in_array($field,$thi
17、s-fields)$this-data$field=$value;else throw new Exception($field does not exist);基类负责数据库连接、参数合法性校验等等,MVC模式,架构模式中的一种属于交互系统场景用户界面会变换界面的变换不影响核心功能性代码有一致的方式来区分并组织好存储、业务、显示相关代码,MVC,MVC框架诞生的11个步骤,区分核心功能和用户交互Model实现变化通知功能,需要吗?参考Observer模式设计和实现view设计和实现Controller响应用户的输入、事件把View和Controller关联起来(怎么相互调用?)MVC框架的初始化动态创建View?动态可扩展的插件系统controller不绑定到特定的view?复用一些基础库,建立层次性的继承体系?与当前业务解耦合,变成一个通用的框架?推广好酒也怕巷子深,抽象,学习方法,读好书站在巨人肩膀上Pattern-Oriented Software Architecture(5本)聆听大师的教诲多实践纸上得来终觉浅,绝知此事要躬行做一个micro framework多交流碰撞,谢谢大家!Q&A,