我们分三篇文章总结设计模式在PHP中的应用。这是第一个创建模式。一、设计模式简介首先,我们先来了解一下什么是设计模式:设计模式是对一组可靠的代码设计经验的总结,可以反复使用,容易被他人理解。设计模式不是Java的专利,我们也可以在PHP中用面向对象的方法很好地使用23种设计模式。那么我们常说的架构、框架、设计模式是什么关系呢?Architecture是一组架构,是项目的整体解决方案;框架是可以重复使用的半成品软件,是具体的程序代码。架构一般涉及使用什么样的框架来加速和优化某些问题的解决,而好的框架代码合理地使用了很多设计模式。2、细化设计模式的几个原则:开闭原则:模块应该对扩展开放,对修改关闭。里氏代换原则:如果调用了父类,也可以用子类代换执行。依赖倒置原则:抽象不依赖细节,面向接口编程,传递参数尽可能引用高层类。接口隔离原则:每个接口只负责一个角色。综合/聚合重用原则:尽量使用综合/聚合,而不是滥用继承。3.设计模式的作用?设计模式可以解决:替换掉乱七八糟的代码,形成良好的代码风格,代码易读,工程师也很容易理解在增加新功能时,不需要修改界面。它具有很强的可扩展性和良好的稳定性。不会有设计模式解决不了的未知问题:设计模式是用来组织你的代码的模板,而不是直接调用的库;设计模式不是最高效的,但代码的可读性和可维护性更重要;不要盲目追求和应用设计模式,重构时要多考虑;四、设计模式的分类1、创建型模式:单例模式、工厂模式(简单工厂、工厂方法、抽象工厂)、创建者模式、原型模式。2.结构模式:Adapter模式、Bridge模式、Decoration模式、Composition模式、Appearance模式、Flyweight模式、Proxy模式。3、行为模式:模板方法模式、命令模式、迭代器模式、观察者模式、中介模式、备忘录模式、解释器模式、状态模式、策略模式、责任链模式、访客模式。五、创建型设计模式1、单例模式的目的:保证一个类只有一个实例,并提供一个全局访问点来访问它。应用场景:数据库连接、缓存操作、分布式存储。/**SingletonMode**/classDbConn{privatestatic$_instance=null;protectedstatic$_counter=0;protected$_db;//私有化构造函数,不允许外部创建实例privatefunction__construct(){self::$_counter+=1;}publicfunctiongetInstance(){if(self::$_instance==null){self::$_instance=newDbConn();}returnsself::$_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关键字就可以变成synchronized,或者在类成员变量定义的时候提前把_intanc的初始化放上去,但这两种方法PHP都不支持。不过因为php不支持多线程,所以不需要考虑这个问题。2.工厂模式实现:定义一个创建对象的接口,让子类决定实例化哪个类。应用场景:子类较多,会扩展,创建方法比较复杂。/***工厂模式*///抽象产品接口Person{publicfunctiongetName();}//具体产品实现classTeacherimplementsPerson{functiongetName(){return"teachern";}}classStudentimplementsPerson{functiongetName(){return"studentn";}}//简单工厂类SimpleFactory{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();}}//工厂方法接口CommFactory{publicfunctiongetPerson();}//具体工厂实现classStudentFactoryimplementsCommFactory{functiongetPerson(){returnnewStudent();}}classTeacherFactoryimplementsCommFactory{functiongetPerson(){returnnewTeacher();}}//工厂方法调用类CommClient{staticfunctionmain(){$factory=newTeacherFactory();echo$factory->getPerson()->getName();$factory=newStudentFactory();echo$factory->getPerson()->getName();}}//抽象工厂模式另一个产品线接口Grade{functiongetYear();}//另一个产品线的具体产品类Grade1实现Grade{publicfunctiongetYear(){return'2003grade';}}classGrade2implementsGrade{publicfunctiongetYear(){return'2004grade';}}//抽象工厂接口AbstractFactory{functiongetPerson();functiongetGrade();}//特定工厂可以为每个产品线生产产品();}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、Creator模式在Creator模式下,客户端不再负责对象的创建和组装,而是将创建对象的责任交给其具体的创建者类,而将组装的责任交给对象组装类。为对象的调用付费,从而明确了各个类的职责。应用场景:创作很复杂,一步一步组装。/**有财网公开课示例代码*创作者模式*///购物车类ShoppingCart{//已选商品private$_goods=array();//使用过的优惠券private$_tickets=array();publicfunctionaddGoods($goods){$this->_goods[]=$goods;}publicfunctionaddTicket($ticket){$this->_tickets[]=$ticket;}publicfunctionprintInfo(){printf("goods:%s,tickets:%sn",implode(',',$this->_goods),implode(',',$this->_tickets));}}//如果我们要恢复购物车,比如当用户关闭浏览器重新打开时,会根据cookie恢复$data=array('goods'=>array('clothes','shoes'),'tickets'=>array('minus10'),);//如果不使用创建者模式,需要在业务类中逐步恢复购物车//$cart=newShoppingCart();//foreach($data['goods']as$goods){//$cart->addGoods($goods);//}//foreach($data['tickets']as$ticket){//$cart->addTicket($ticket);//}//$cart->printInfo();//exit;//我们提供了一个creator类来封装购物车类CardBuilder的数据组装{private$_card;function__construct($card){$this->_card=$card;}functionbuild($data){foreach($data['goods']as$goods){$this->_card->addGoods($goods);}foreach($data['tickets']as$tticket){$this->_card->addTicket($ticket);}}functiongetCrad(){return$this->_card;}}$cart=newShoppingCart();$builder=newCardBuilder($cart);$builder->build($data);echo"afterbuilder:n";$cart->printInfo();?>可以看出,使用creator模式封装内部数据复杂对象的数据组装过程后,对外接口会非常简单和规范,增加和修改新的数据项不会对外部造成任何影响。原型模式使用原型实例来指定要创建的对象的类型,通过复制原型来创建新的对象。应用场景:类的资源较多,对性能和安全性有要求,一般与工厂方法结合使用。/**Prototype模式//声明一个克隆自身的接口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,%sn",$this->school,$this->major,$this->name);}publicfunctioncopy(){returnclone$this;}}$stu1=newStudent('清华大学','计算机','张三');$stu1->printInfo();$stu2=$stu1->copy();$stu2->name='李四';$stu2->printInfo();?>这里可以看出,如果类的成员变量比较多,如果从外部创建多个new对象,然后一一赋值,效率并不高,代码冗余也容易出错,通过prototype复制复制本身的Minormodification是另一个newobject。设计模式的第一部分,创建模式到此结束。下面分为两部分:结构设计模式和行为设计模式,下次继续分享。
