享乐模式,“享”字其实在中文里并没有什么特殊的意思,所以我们要拆开来看。“分”是共享,“元”是元素,这样看起来很容易理解,共享某些元素。GoF类图及解释GoF定义:使用共享技术有效支持大量细粒度对象101;functionoperation($extrinsicState):void{echo'共享享元对象'.($extrinsicState+$this->intrinsicState)。PHP_EOL;}}类UnsharedConcreteFlyweight实现Flyweight{private$allState=1000;publicfunctionoperation($extrinsicState):void{echo'非共享享元对象:'.($extrinsicState+$this->allState).PHP_EOL;}}定义共享接口及其实现。请注意,这里有两个实现。ConcreteFlyweight共享状态,UnsharedConcreteFlyweight不共享或者他的状态不需要共享classFlyweightFactory{private$flyweights=[];publicfunctiongetFlyweight($key):Flyweight{if(!array_key_exists($key,$this->flyweights)){$this->flyweights[$key]=newConcreteFlyweight();}返回$this->flyweights[$key];}}保存那些需要共享的对象,作为创建所需共享对象的工厂,保留证明相同键值下只会有唯一对象,节省创建相同对象的成本$factory=newFlyweightFactory();$extrinsicState=100;$flA=$factory->getFlyweight('a');$flA->操作(--$extrinsicState);$flB=$factory->getFlyweight('b');$flB->operation(--$extrinsicState);$flC=$factory->getFlyweight('c');$flC->operation(--$extrinsicState);$flD=newUnsharedConcreteFlyweight();$flD->operation(--$extrinsicState);客户端调用,让外部状态$extrinsicState可以在各个对象间共享,有点意思,这种模式的代码量不小。当一个应用程序使用大量非常相似的对象,并且大部分对象都可以更改为外部状态时,非常适合享元模式。这里的工厂存储的是对象列表,不像工厂方法或者抽象工厂是用来创建对象的。虽然也是在这里创建的,但是如果对象存在,会直接返回,列表也是一直维护的享元模型。现实中想必大家或多或少都用过。各种pools技术是它的典型应用:线程池,连接池等。另外两个相同String类型的字符串在php或者java中可以是===,享元模式也有应用,它们甚至还有内存地址.一样的,这不就是一种分享吗?关于享元模式,有一个极其经典的例子,比下面这个例子好太多了,就是围棋的棋盘只有黑白色,两个对象就够了OK,接下来呢?只是改变他们的位置状态!有兴趣的朋友可以搜索哈!Laravel中的IoC容器可以看作享元模式的一种实现。它将对象保存在一个数组中,并在需要时通过闭包机制访问它们。还有一些类共享一些状态属性。你可以阅读代码来理解。或者说到技术是基于改变外壳的事实。毕竟大家还是喜欢各种颜色的手机来彰显个性。我之前说过,如果我们必须为每个颜色都做一条生产线,那不是一个巨大的投资吗?幸运的是,我们工厂(祥园工厂)只为每个模型生产最基本的背景外壳(物体),然后通过特殊的印刷线(状态变化)进行着色!那么,下一款Iphone迟早会模仿我们。看来还是得先把各种金灿灿的颜色都收集齐了,说不定还能召唤神龙呢!!完整代码:https://github.com/zhangyue0503/designpatterns-php/blob/master/13.flyweights/source/flyweights.php示例果然不出意外,我们还是发短信,这次短信还是用的使用阿里云和极光短信发送,但是这次我们使用享元模式来实现。我们在这里的享元工厂中保存了两种不同类型的对象。让我们通过内部和外部状态让它们不断变化!短信发送类图完整源码:https://github.com/zhangyue0503/designpatterns-php/blob/master/13.flyweights/source/flyweights-message.phptemplate=$template;}publicfunctionsend(User$user){echo'使用阿里云短信到'.$user->GetName().'发送:';echo$this->template->GetTemplate(),PHP_EOL;}}classJiGuangMessageimplementsMessage{private$template;公共函数__construct($template){$this->template=$template;}publicfunctionsend(User$user){echo'使用极光短信向'.$用户->GetName()。'发送:';echo$this->template->GetTemplate(),PHP_EOL;}}classMessageFactory{private$messages=[];公共函数GetMessage(Template$template,$type='ali'){$key=md5($template->GetTemplate().$type);if(!key_exists($key,$this->messages)){if($type=='ali'){$this->messages[$key]=newAliYunMessage($template);}}else{$this->messages[$key]=newJiGuangMessage($template);}}返回$this->messages[$key];}publicfunctionGetMessageCount(){echocount($this->messages);}}classUser{public$name;公共函数GetName(){返回$this->name;}}类模板{public$template;publicfunctionGetTemplate(){return$this->template;}}}//内部状态$t1=newTemplate();$t1->template='模板1,不错!';$t2=newTemplate();$t2->template='模板2,好的!';//外部状态$u1=newUser();$u1->name='张三';$u2=newUser();$u2->name='李四';$u3=newUser();$u3->name='王舞';$u4=newUser();$u4->name='赵六';$u5=newUser();$u5->name='田七';//享元工厂$factory=newMessageFactory();//阿里云发送$m1=$factory->GetMessage($t1);$m1->send($u1);$m2=$factory->GetMessage($t1);$m2->send($u2);echo$factory->GetMessageCount(),PHP_EOL;//1$m3=$factory->GetMessage($t2);$m3->send($u2);$m4=$factory->GetMessage($t2);$m4->send($u3);echo$factory->GetMessageCount(),PHP_EOL;//2$m5=$factory->GetMessage($t1);$m5->send($u4);$m6=$factory->GetMessage($t2);$m6->send($u5);echo$factory->GetMessageCount(),PHP_EOL;//2//加入极光$m1=$factory->GetMessage($t1,'jg');$m1->send($u1);$m2=$factory->GetMessage($t1);$m2->send($u2);echo$factory->GetMessageCount(),PHP_EOL;//3$m3=$factory->GetMessage($t2);$m3->send($u2);$m4=$factory->GetMessage($t2,'jg');$m4->send($u3);echo$factory->GetMessageCount(),PHP_EOL;//4$m5=$factory->GetMessage($t1,'jg');$m5->发送($u4);$m6=$factory->GetMessage($t2,'jg');$m6->send($u5);echo$factory->GetMessageCount(),PHP_EOL;//4说明代码很多,但实际上有两种类型的类,生成了四种对象。每个类的不同对象是根据模板来区分的。想想哦!享元模式适用于系统中存在大量相似对象,需要缓冲池的场景。它可以减少内存使用,提高效率,但会增加复杂度。共享内部和外部状态的主要特点是有一个唯一的标识符。当内存中已经有这个对象时,直接返回对象,不需要重新创建。这方面的典型例子太经典了。无论如何,只要记住它的特性即可。应用的时候,你可能写不下代码回头看看,你会发现这就是我学的享元模式!好吧,在下一篇文章中,我们将学习一个比较罕见和复杂的模式,但也许你能经常看到它!各媒体平台均可搜索组合模式【硬核项目经理】
