设计模式之享元模式(十八)

  以前想骑自行车需要去自行车店里购买,才能骑自行车。现在有了共享单车,我们则不需要购买单车,只需要扫描二维码就可以来一场说走就走的短途。共享单车的这种模式,我们可以理解为享元模式。

一、享元模式的定义

  所谓享元模式就是运行共享技术有效地支持大量细粒度(对象的相似度比较高的属性)对象的复用。系统使用少量对象,而且这些对象都比较相似,状态变化小,可以实现对象的多次复用。


二、享元模式类图


三、享元模式的角色

  • Flyweight
    抽象享元类。所有具体享元类的超类或者接口。Flyweight可以接受并作用于外部状态。

  • ConcreteFlyweight
    具体享元类。指定内部状态,为内部状态增加存储空间。

  • UnsharedConcreteFlyweight
    非共享具体享元类。指出那些不需要共享的Flyweight子类。

  • FlyweightFactory
    享元工厂类。用来创建并管理Flyweight对象,它主要用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)。


四、情景代码

小明、小王、小李三个人要骑自行车,接下来我们用代码来实现。

  • 自行车类
public class Bicycle {

private  String name;

public Bicycle (String name) {
    this.name = name;
}

public void  rideBicycle () {
    System.out.println(name+" 骑自行车");
}

}
  • 测试类
public static void main(String[] args) {
    Bicycle bicycle1 = new Bicycle("小明");
    bicycle1.rideBicycle();

    Bicycle bicycle2 = new Bicycle("小王");
    bicycle2.rideBicycle();

    Bicycle bicycle3 = new Bicycle("小李");
    bicycle3.rideBicycle();
}

  通过上面的例子,我们可以看出,谁要骑车都需要创建一个对象,对象都是相同的,这样对内存消耗是比较大的,而且也不符合设计模式编程。接下来我们用享元模式来实现。

  • 定义一个车类的接口
public interface Car {
       public void  rideCar (String userName);
}
  • 非享元的实现类
public class CarNoImpl implements Car {

@Override
public void rideCar(String userName) {
    System.out.println(userName+"骑单车");
}
}
  • 享元工厂类
public class CarFactory {
      //  享元池
      //  如果找到了,不需要创建新的对象。包含了两个意思,第一个意思:减少了对象的创建,第二个,提高了对象的重复利用。
      private static Map<String,Object> filweighs = new HashMap<String,Object>();

      public Car getCar(String key,Car car) {
             if (!filweighs.containsKey(key)) {
                  filweighs.put(key, car);
             }
          return (Car) filweighs.get(key);
      }
}
  • 测试类
public static void main(String[] args) {

   CarFactory carFactory = new CarFactory();
   Car car1 = carFactory.getCar("红色",new CarNoImpl());
   car1.rideCar("小明");

   Car car2 = carFactory.getCar("蓝色",new CarNoImpl());
   car2.rideCar("小王");

   Car car3 = carFactory.getCar("红色",new CarNoImpl());
   car3.rideCar("小李");
}
  • 测试结果
 小明骑自行车
 小王骑自行车
 小李骑自行车

  小明、小李骑的是红色的单车,这时我们的享元工厂是通过颜色查找,如果集合中有这个对象,则不需要创建直接返回集合中的对象,如果没有则需要创建对象,下次直接获取享元池中的对象,这样避免频繁创建对象。

接下来我们来聊聊共享部分,也就是外部状态。

  • 享元实现类
public class CarOkImpl implements Car {

public Car car;

public CarOkImpl(Car car) {
    this.car = car;
}

@Override
public void rideCar(String userName) {
    if (null == car) {
        System.out.println("附近没有单车可骑");
        return;
    }
    car.rideCar(userName);
}
}
  • 测试类
public static void main(String[] args) {

   Car car4 = carFactory.getCar("黑色",new CarOkImpl(null));
   car4.rideCar("小王");

}
  • 测试结果
 附近没有单车可骑

  测试我们发现非享元实现类是不会改变内部类的状态,享元实现类是通过客户端可以改变内部类的状态。
  这就是享元的模式的两种状态,内部状态和外部状态。
  内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。


五、享元模式的优缺点

  • 优点

  1、享元模式的优点在于它能够极大的减少系统中对象的个数。
  2、享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

  • 缺点

  1、由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。
  2、为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。


六、适用场景

  如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。
  对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。


七、小结

  享元模式可以极大地减少系统中对象的数量。但是它可能会引起系统的逻辑更加复杂化。享元模式的核心在于享元工厂,它主要用来确保合理地共享对象。
  内部状态为不变共享部分,存储于享元对象内部,而外部状态是可变部分,它应当客户端来负责。


源码在这里GitHub:
https://github.com/xiaonongOne/flyweight

注意啦! 往期设计模式在这里

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,732评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,496评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,264评论 0 338
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,807评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,806评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,675评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,029评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,683评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,704评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,666评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,773评论 1 332
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,413评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,016评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,978评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,204评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,083评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,503评论 2 343

推荐阅读更多精彩内容