php设计模式(一):简介及创建型模式
我们分三篇文章来总结一下设计模式在PHP中的应用,这是第一篇创建型模式。
一、设计模式简介:
首先我们来认识一下什么是设计模式:
设计模式是一套被反复使用、容易被他人理解的、可靠的代码设计经验的总结。
设计模式不是Java的专利,我们用面向对象的方法在PHP里也能很好的使用23种设计模式。
那么我们常说的架构、框架和设计模式有什么关系呢?
架构是一套体系结构,是项目的整体解决方案;框架是可供复用的半成品软件,是具体程序代码。架构一般会涉及到采用什么样的框架来加速和优化某部分问题的解决,而好的框架代码里合理使用了很多设计模式。
二、提炼设计模式的几个原则:
开闭原则:模块应对扩展开放,而对修改关闭。
里氏代换原则:如果调用的是父类的话,那么换成子类也完全可以运行。
依赖倒转原则:抽象不依赖细节,面向接口编程,传递参数尽量引用层次高的类。
接口隔离原则:每一个接口只负责一种角色。
合成/聚合复用原则:要尽量使用合成/聚合,不要滥用继承。
三、设计模式的功用:
1、设计模式能解决
替换杂乱无章的代码,形成良好的代码风格
代码易读,工程师们都能很容易理解
增加新功能时不用修改接口,可扩展性强
稳定性好,一般不会出现未知的问题
2、设计模式不能解决
设计模式是用来组织你的代码的模板,而不是直接调用的库;
设计模式并非最高效,但是代码的可读性和可维护性更重要;
不要一味追求并套用设计模式,重构时多考虑;
四、设计模式分类
1、创建型模式:
单例模式、工厂模式(简单工厂、工厂方法、抽象工厂)、创建者模式、原型模式。
2、结构型模式:
适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3、行为型模式:
模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式。
五、创建型设计模式
1、单例模式
目的:保证一个类仅有一个实例,并提供一个访问它的全局访问点。
应用场景:数据库连接、缓存操作、分布式存储。
<?php/***优才网公开课示例代码**单例模式**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*/classDbConn{privatestatic$_instance=null;protectedstatic$_counter=0;protected$_db;//私有化构造函数,不允许外部创建实例privatefunction__construct(){self::$_counter+=1;}publicfunctiongetInstance(){if(self::$_instance==null){self::$_instance=newDbConn();}returnself::$_instance;}publicfunctionconnect(){echo"connected:".(self::$_counter)."\n";return$this->_db;}}
/**不使用单例模式时,删除构造函数的private后再测试,第二次调用构造函数后,_counter变成2*///$conn=newDbConn();//$conn->connect();//$conn=newDbConn();//$conn->connect();//使用单例模式后不能直接new对象,必须调用getInstance获取$conn=DbConn::getInstance();$db=$conn->connect();//第二次调用是同一个实例,_counter还是1$conn=DbConn::getInstance();$db=$conn->connect();?>
特别说明:这里getInstance里有if判断然后再生成对象,在多线程语言里是会有并发问题的。例如java的解决方案有二个,给方法加上synchronized关键词变成同步,或者把_instanc的初始化提前放到类成员变量定义时,但是这2种方式php都不支持。不过因为php不支持多线程所以不需要考虑这个问题了。
2、工厂模式
实现:定义一个用于创建对象的接口,让子类决定实例化哪一个类。
应用场景:众多子类并且会扩充、创建方法比较复杂。
<?php/***优才网公开课示例代码**工厂模式**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*///抽象产品interfacePerson{publicfunctiongetName();}//具体产品实现classTeacherimplementsPerson{functiongetName(){return"老师\n";}}classStudentimplementsPerson{functiongetName(){return"学生\n";}}//简单工厂classSimpleFactory{publicstaticfunctiongetPerson($type){$person=null;if($type=='teacher'){$person=newTeacher();}elseif($type=='student'){$person=newStudent();}return$person;}}//简单工厂调用classSimpleClient{functionmain(){//如果不用工厂模式,则需要提前指定具体类//$person=newTeacher();//echo$person->getName();//$person=newStudent();//echo$person->getName();//用工厂模式,则不需要知道对象由什么类产生,交给工厂去决定$person=SimpleFactory::getPerson('teacher');echo$person->getName();$person=SimpleFactory::getPerson('student');echo$person->getName();}}//工厂方法interfaceCommFactory{publicfunctiongetPerson();}//具体工厂实现classStudentFactoryimplementsCommFactory{functiongetPerson(){returnnewStudent();}}classTeacherFactoryimplementsCommFactory{functiongetPerson(){returnnewTeacher();}}//工厂方法调用classCommClient{staticfunctionmain(){$factory=newTeacherFactory();echo$factory->getPerson()->getName();$factory=newStudentFactory();echo$factory->getPerson()->getName();}}//抽象工厂模式另一条产品线interfaceGrade{functiongetYear();}//另一条产品线的具体产品classGrade1implementsGrade{publicfunctiongetYear(){return'2003级';}}classGrade2implementsGrade{publicfunctiongetYear(){return'2004级';}}//抽象工厂interfaceAbstractFactory{functiongetPerson();functiongetGrade();}//具体工厂可以产生每个产品线的产品classGrade1TeacherFactoryimplementsAbstractFactory{publicfunctiongetPerson(){returnnewTeacher();}publicfunctiongetGrade(){returnnewGrade1();}}classGrade1StudentFactoryimplementsAbstractFactory{publicfunctiongetPerson(){returnnewStudent();}publicfunctiongetGrade(){returnnewGrade1();}}classGrade2TeacherFactoryimplementsAbstractFactory{publicfunctiongetPerson(){returnnewTeacher();}publicfunctiongetGrade(){returnnewGrade2();}}//抽象工厂调用classFactoryClient{functionprintInfo($factory){echo$factory->getGrade()->getYear().$factory->getPerson()->getName();}functionmain(){$client=newFactoryClient();$factory=newGrade1TeacherFactory();$client->printInfo($factory);$factory=newGrade1StudentFactory();$client->printInfo($factory);$factory=newGrade2TeacherFactory();$client->printInfo($factory);}}//简单工厂//SimpleClient::main();//工厂方法//CommClient::main();//抽象工厂FactoryClient::main();?>
三种工厂的区别是,抽象工厂由多条产品线,而工厂方法只有一条产品线,是抽象工厂的简化。而工厂方法和简单工厂相对,大家初看起来好像工厂方法增加了许多代码但是实现的功能和简单工厂一样。但本质是,简单工厂并未严格遵循设计模式的开闭原则,当需要增加新产品时也需要修改工厂代码。但是工厂方法则严格遵守开闭原则,模式只负责抽象工厂接口,具体工厂交给客户去扩展。在分工时,核心工程师负责抽象工厂和抽象产品的定义,业务工程师负责具体工厂和具体产品的实现。只要抽象层设计的好,框架就是非常稳定的。
3、创建者模式
在创建者模式中,客户端不再负责对象的创建与组装,而是把这个对象创建的责任交给其具体的创建者类,把组装的责任交给组装类,客户端支付对对象的调用,从而明确了各个类的职责。
应用场景:创建非常复杂,分步骤组装起来。
<?php/***优才网公开课示例代码**创建者模式**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*///购物车classShoppingCart{//选中的商品private$_goods=array();//使用的优惠券private$_tickets=array();publicfunctionaddGoods($goods){$this->_goods[]=$goods;}publicfunctionaddTicket($ticket){$this->_tickets[]=$ticket;}publicfunctionprintInfo(){printf("goods:%s,tickets:%s\n",implode(',',$this->_goods),implode(',',$this->_tickets));}}//假如我们要还原购物车的东西,比如用户关闭浏览器后再打开时会根据cookie还原$data=array('goods'=>array('衣服','鞋子'),'tickets'=>array('减10'),);//如果不使用创建者模式,则需要业务类里一步步还原购物车//$cart=newShoppingCart();//foreach($data['goods']as$goods){//$cart->addGoods($goods);//}//foreach($data['tickets']as$ticket){//$cart->addTicket($ticket);//}//$cart->printInfo();//exit;//我们提供创建者类来封装购物车的数据组装classCardBuilder{private$_card;function__construct($card){$this->_card=$card;}functionbuild($data){foreach($data['goods']as$goods){$this->_card->addGoods($goods);}foreach($data['tickets']as$ticket){$this->_card->addTicket($ticket);}}functiongetCrad(){return$this->_card;}}$cart=newShoppingCart();$builder=newCardBuilder($cart);$builder->build($data);echo"afterbuilder:\n";$cart->printInfo();?>
可以看出,使用创建者模式对内部数据复杂的对象封装数据组装过程后,对外接口就会非常简单和规范,增加修改新数据项也不会对外部造成任何影响。
4、原型模式
用原型实例指定创建对象的种类,并且通过拷贝这个原型来创建新的对象。
应用场景: 类的资源非常多、性能和安全要求,一般和工厂方法结合使用。
<?php/***优才网公开课示例代码**原型模式**@author优才网全栈工程师教研组*@seehttp://www.ucai.cn*///声明一个克隆自身的接口interfacePrototype{functioncopy();}//产品要实现克隆自身的操作classStudentimplementsPrototype{//简单起见,这里没有使用getsetpublic$school;public$major;public$name;publicfunction__construct($school,$major,$name){$this->school=$school;$this->major=$major;$this->name=$name;}publicfunctionprintInfo(){printf("%s,%s,%s\n",$this->school,$this->major,$this->name);}publicfunctioncopy(){returnclone$this;}}$stu1=newStudent('清华大学','计算机','张三');$stu1->printInfo();$stu2=$stu1->copy();$stu2->name='李四';$stu2->printInfo();?>
这里可以看到,如果类的成员变量非常多,如果由外部创建多个新对象再一个个赋值,则效率不高代码冗余也容易出错,通过原型拷贝复制自身再进行微小修改就是另一个新对象了。
设计模式的第一部分,创建型模式就总结完了。下面还有两部分结构型设计模式和行为型设计模式稍后继续。
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。