Zer0e's Blog

设计模式之享元模式

字数统计: 753阅读时长: 2 min
2020/09/17 Share

前言

本文谈谈享元模式。

正文

概念

享元模式属于结构型模式,它主要是缓存重复的对象,以减少内存的消耗,这些相同的对象往往需要重复的使用,如果不对其进行缓存,可能会导致内存溢出。那享元模式一般配合工厂模式一起使用。
常见的应用场景有Java中的String,在创建String时判断缓存池里是否有这个字符串,有的话直接返回,没有才进行创建。

实现

享元模式中有以下几个角色:

  • 抽象享元类(Flyweight):接口或者抽象类,声明公共方法。
  • 具体享元类(ConcreteFlyweight):实现抽象享元类,结合单例模式提供唯一的对象。
  • 享元工厂类(FlyweightFactory):用来创建及管理享元对象,可以参考工厂模式。

这里我们举个简单例子,一般商店里的物品不止一样,那么我们可以把同一个名称的商品作为共享的。
我们创建抽象接口FlyWeight

1
2
3
public interface FlyWeight {
public void sell();
}

接着我们可以创建商品类

1
2
3
4
5
6
7
8
9
10
11
12
public class Item implements FlyWeight{
private String name;

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

@Override
public void sell() {
System.out.println("卖出一件商品: " + name);
}
}

创建工厂类:

1
2
3
4
5
6
7
8
9
10
11
12
13
public class FlyWeightFactory {
private Map<String,Item> map = new HashMap<>();
public Item getItem(String name){
Item item = null;
if (map.containsKey(name)){
item = map.get(name);
}else{
item = new Item(name);
map.put(name,item);
}
return item;
}
}

那么客户端调用也很简单,商品从工厂类中获取即可

1
2
3
4
5
6
7
8
9
10
11
public class Client {
public static void main(String[] args) {
FlyWeightFactory flyWeightFactory = new FlyWeightFactory();
Item milk1 = flyWeightFactory.getItem("牛奶");
Item milk2 = flyWeightFactory.getItem("牛奶");
System.out.println(milk1 == milk2);//true

milk1.sell();
milk2.sell();
}
}

那以上例子还可以继续细化,比如Item类作为抽象类,而具体商品则继承它,那具体商品就可以有更多的属性,比如价格,批次等等。那在工厂类添加的时候可能需要根据传入名称来创建类,具体可以使用反射机制,这里就不再展开。
总而言之,享元模式中共享的对象是同一个,实现这个模式常常结合工厂模式,单例模式来使用,需要注意的是在多线程中需要使用线程安全的容器来存储对象。

优缺点

享元模式优点很明显,可以减少重复对象的创建,减低内存使用率。
那缺点可能就是需要区分外部状态与内部状态,内部状态不随环境改变,可共享,外部状态岁环境改变,不能共享。也就是上文例子中name作为外部状态可改变,如果再添加一个无法更改的属性比如价格,那么就是内部状态,无法被更改。
所以享元模式一定程度上增加了系统的复杂性。

CATALOG
  1. 1. 前言
  2. 2. 正文
    1. 2.1. 概念
    2. 2.2. 实现
    3. 2.3. 优缺点