享元模式初探

前言

上文《策略模式初探》中讲到策略模式会产生重复策略类,对内存来说是一种浪费。

这篇文章主要介绍享元模式如何去处理这种问题。


什么是享元模式呢

从字面上如何理解:

  • 享: 共享,分享
  • 元: 元素,共同部分,属性
  • 模式: 一种方法

也就是说 ++享元模式是一种将共同部分共享起来的方法++。

那么就符合我们的需求了--共享相同的策略类。

模式相关概念介绍

  • 内部状态:内部的,可以共享的元素。
  • 外部状态:外部的,不可以共享的元素。

享元模式主要针对内部状态,也就是可以共享的元素进行操作。

  • 主要的角色
    1. 抽象享元角色:给享元角色规定必须实现的方法。
    2. 具体享元角色:继承抽象享元角色,也就是对内部状态进行共享。
    3. 享元工厂角色:负责创建和管理享元角色,维护一个共享池。
    4. 客户端角色:维护对所有享元对象的引用,并指定外部状态。

例子及代码

同样的用上篇文章《策略模式初探》的例子。

假如公司有5000人,每个人都要选择一种上班方式。

那么,在内存中就会存在N多相同的对象。

在享元模式概念中,上班方式就是一种内部状态,是不会改变的,而人会改变,所以人是一种外部状态。应该由客户端去指定。

如果用享元模式该怎么处理呢?


 //抽象享元角色
 interface Way {
     public function way($user);
 }

 //具体享元角色
 class WalkWay implements Way {

     public function way($user) {
         echo $user.'走路去公司!';
     }
 }

 class BikeWay implements Way {

     public function way ($user) {
         echo $user.'骑单车去公司!';
     }
 }

 class HappyWay implements Way {

     public function way ($user) {
         echo $user.'今天休息!';
     }
 }

 //享元工厂
 class ConFactory {

     //共享池
     private $con = [];

     public function instance($class)
     {
         if ( isset($this->con[$class]) ) {
             return $this->con[$class];
         } 

         try {
             $c = new ReflectionClass($class);

             $this->con[$class] = $c->newInstance();

             return  $this->con[$class];
         } catch ( ReflectionException $e) {
             echo '你要的方式木有哦!';
             return null;
         }
     }
 }

 //客户端

 $f = new ConFactory();

 $me = $f->instance('HappyWay');
 $me->way('我'); // 我今天休息!

 $he = $f->instance('WalkWay');
 $me->way('他'); //他走路去公司!

 $she = $f->instance('BikeWay');
 $she->way('她');//她骑单车去公司!

 $lisi = $f->instance('WalkWay');
 $lisi->way('李四'); //李四走路去公司! 李四就会直接使用共享池中的实例而不用创建新的。

总结

从上面的例子中可以看到,能够被共享的元素是维护在一个共享池中的,如骑单车,走路。而不能共享的元素是从客户端传入的,如李四。这样做确实可以确保这些“策略”(去公司的方式)不会重复实例化。但却增加了系统的复杂程度,所以具体怎么选择得好好衡量一下。

本作品采用《CC 协议》,转载必须注明作者和本文链接
《L04 微信小程序从零到发布》
从小程序个人账户申请开始,带你一步步进行开发一个微信小程序,直到提交微信控制台上线发布。
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
讨论数量: 6

也就是Laravel的容器吧

5年前 评论

感觉对 CI/IOC 控制反转 这么说就很清楚明白了

5年前 评论

@bibace IOC可以看作更复杂的享元或工厂

5年前 评论

请教下,类能extends接口吗?,文中代码 class WalkWay extends Way,而 Way是interface(接口),

5年前 评论

@燕飞 不能哈,文中写错了,已改正:smile:

5年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!