字节跳动飞书内推!
北京、杭州、武汉、广州、深圳、上海,六大城市等你来投。
感兴趣的朋友可以私我咨询&内推,也可以通过链接直接投递!
海量HC,极速响应,快来和我成为同事吧。
今日头条、抖音、Tik Tok也可以内推~
点击进入我的博客
享元模式以共享的方式高效地支持大量的细粒度对象。
3.6.1 单纯享元模式
单纯享元模式中,所有的享元对象都是可以共享的。
单纯享元模式
- 抽象享元(Flyweight)角色:是所有具体享元角色的超类,并为这些类规定公共接口。
- 具体享元(Concrete Flyweight)角色:实现抽象享元的接口。如果由内蕴状态的话,必须负责为内蕴状态提供空间。
- 享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。如果系统中有了则返回该角色,没有则创建。
- 客户端(Client)角色:维护一个所有享元对象的引用。存储所有享元对象的外蕴状态。
3.6.2 复合享元模式
复合享元模式
- 抽象享元(Flyweight)角色 :给出一个抽象接口,以规定出所有具体享元角色需要实现的方法。
- 具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态的话,必须负责为内蕴状态提供存储空间。
- 复合享元(ConcreteCompositeFlyweight)角色 :复合享元角色所代表的对象是不可以共享的,但是一个复合享元对象可以分解成为多个本身是单纯享元对象的组合。复合享元角色又称作不可共享的享元对象(UnsharedConcreteFlyweight)。
- 享元工厂(FlyweightFactory)角色 :负责创建和管理享元角色。当一个客户端对象调用一个享元对象的时候,如果已经有了,享元工厂角色就应当提供这个已有的享元对象;如果系统中没有一个适当的享元对象的话,享元工厂角色就应当创建一个合适的享元对象。
3.6.3 细节
内蕴状态和外蕴状态
内蕴状态:是存储在享元对象内部的,不会随环境改变而改变的。一个享元可以具有内蕴状态并可以共享。
外蕴状态:随环境改变而改变、不可以共享的状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传入到享元对象内部。
不变模式
享元模式中的对象不一定非要是不变对象,但大多数享元对象的确是这么设计的。
享元工厂
- 使用单例模式:一般只需要一个享元工厂,可以设计成单例的。
- 备忘录模式:享元工厂负责维护一个表,通过这个表把很多相同的实例与它们的一个对象联系起来。
优点
减少对象的创建,降低内存消耗
缺点
- 提高了系统的复杂度,为了使对象可以共享,需要将一些状态外部化
- 需要将一些状态外部化,而读取外部状态是的运行时间稍微变长
使用场景
- 一个系统中有大量对象。
- 这些对象消耗大量内存。
- 这些对象的状态大部分可以外部化。
- 这些对象可以按照内蕴状态分为很多组,当把外蕴对象从对象中剔除出来时,每一组对象都可以用一个对象来代替。
- 系统不依赖于这些对象身份,换言之,这些对象是不可分辨的。
Java应用
- String对象,有则返回,没有则创建一个字符串并保存
- 数据库的连接池
3.6.4 案例
依旧是熟悉的KFC点餐为例:
- 外蕴状态:点餐的顾客
- 内蕴状态:顾客点的食物
- 具体享元角色:维护内蕴状态(客人要点的食物)。
public class KFC {
public static void main(String[] args) {
OrderFactory orderFactory = OrderFactory.getInstance();
Order order = orderFactory.getOrder(Food.MiniBurger);
order.operation("李雷");
order = orderFactory.getOrder(Food.MiniBurger);
order.operation("韩梅梅");
}
}
enum Food {
MiniBurger,
MexicanTwister,
CornSalad,
HotWing,
PepsiCola
}
// Flyweight角色
interface Order {
// 传入的是外蕴对象:顾客
void operation(String customer);
}
// ConcreteFlyweight角色
class FoodOrder implements Order {
// 内蕴状态
private Food food;
// 构造方法,传入享元对象的内部状态的数据
public FoodOrder(Food food) {
this.food = food;
}
@Override
public void operation(String customer) {
System.out.println("顾客[" + customer + "]点的是" + food.toString());
}
}
// FlyweightFactory角色
class OrderFactory {
private Map<Food, Order> orderPool = new HashMap<>();
private static OrderFactory instance = new OrderFactory();
private OrderFactory() {}
public static OrderFactory getInstance() {
return instance;
}
// 获取Food对应的享元对象
public Order getOrder(Food food) {
Order order = orderPool.get(food);
if (null == order) {
order = new FoodOrder(food);
orderPool.put(food, order);
}
return order;
}
}