享元模式初探

維C發表於2018-07-23

上文《策略模式初探》中講到策略模式會產生重複策略類,對記憶體來說是一種浪費。

這篇文章主要介紹享元模式如何去處理這種問題。


從字面上如何理解:

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

也就是說 ++享元模式是一種將共同部分共享起來的方法++。

那麼就符合我們的需求了--共享相同的策略類。

  • 內部狀態:內部的,可以共享的元素。
  • 外部狀態:外部的,不可以共享的元素。

享元模式主要針對內部狀態,也就是可以共享的元素進行操作。

  • 主要的角色
    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 協議》,轉載必須註明作者和本文連結

三海

相關文章