享元模式

来源:互联网 发布:淘宝网在哪里领红包 编辑:程序博客网 时间:2024/06/05 18:10

享元模式定义
英文定义:A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects
中文定义:享元模式运用共享技术有效地支持大量细粒度的对象。

享元模式UML图(来自Google图片)

享元模式


抽象享元(Flyweight)角色:是给实现享元提供的接口。
具体享元(ConcreteFlyweight)角色:实现抽象角色,此对象必须是共享的,所含的状态必须是内部状态。
不共享享元(UnSharedConcreteFlyweight)角色:此对象不可共享,不是所有实现抽象享元接口的的对象都要共享,此对象通常将ConcreteFlyweight作为组成元素。
享元模式使用场景(摘自《大话设计模式》)
在襄垣对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态,随环境改变而改变的、不可以共享的状态就是外部状态了。事实上,享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。也就是说,享元模式Flyweight执行时所需要的状态是有内部的也可能有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。
如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;还有就是对象的大多数状态可以外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。

在Java中,String类型就是使用了享元模式。String对象是final类型,对象一旦创建就不可改变。在Java中字符串常量都是存在常量池中的,Java会确保一个字符串常量在常量池中只有一个拷贝。

享元模式源码示例

享元模式原型

public abstract class FlyWeight {    public abstract void operation(int state);}public class ConcreteFlyWeight extends FlyWeight {    @Override    public void operation(int state) {        System.out.println("Concrete Flyweight Information: " + state);    }}public class FlyWeightFactory {    private Map<String, FlyWeight> flyweightMap = new HashMap<String, FlyWeight>();    public FlyWeightFactory() {        // 这里我们初始化三个对象        flyweightMap.put("X", new ConcreteFlyWeight());        flyweightMap.put("X", new ConcreteFlyWeight());        flyweightMap.put("X", new ConcreteFlyWeight());    }    public FlyWeight getFlyWeight(String key) {        //当客户端要求生成一个对象时,工厂会检测是否存在此对象的实例,如果存在那么直接返回此对象实例,如果不存在就创建一个并保存起来,这点有些单例模式的意思。        FlyWeight flyWeight = flyweightMap.get(key);        if (null == flyWeight) {            flyWeight = new ConcreteFlyWeight();            flyweightMap.put(key, flyWeight);        }        return flyWeight;    }}public class Client {    public static void main(String[] args) {        FlyWeightFactory factory = new FlyWeightFactory();        FlyWeight flyWeightX = factory.getFlyWeight("X");        flyWeightX.operation(2);        FlyWeight flyWeightA = factory.getFlyWeight("A");        flyWeightA.operation(1);    }}

一个实例:

import java.util.concurrent.CopyOnWriteArrayList;import java.util.HashMap;import java.util.List;import java.util.Map;// Instances of CoffeeFlavour will be the Flyweightsclass CoffeeFlavour {  private final String name;  CoffeeFlavour(String newFlavor) {    this.name = newFlavor;  }  @Override  public String toString() {    return name;  }}// Menu acts as a factory and cache for CoffeeFlavour flyweight objectsclass Menu {  private Map<String, CoffeeFlavour> flavours = new HashMap<String, CoffeeFlavour>();  CoffeeFlavour lookup(String flavorName) {    if (!flavours.containsKey(flavorName))      flavours.put(flavorName, new CoffeeFlavour(flavorName));    return flavours.get(flavorName);  }  int totalCoffeeFlavoursMade() {    return flavours.size();  }}class Order {  private final int tableNumber;  private final CoffeeFlavour flavour;  Order(int tableNumber, CoffeeFlavour flavor) {    this.tableNumber = tableNumber;    this.flavour = flavor;  }  void serve() {    System.out.println("Serving " + flavour + " to table " + tableNumber);  }}public class CoffeeShop {  private final List<Order> orders = new CopyOnWriteArrayList<Order>();  private final Menu menu = new Menu();  void takeOrder(String flavourName, int table) {    CoffeeFlavour flavour = menu.lookup(flavourName);    Order order = new Order(table, flavour);    orders.add(order);  }  void service() {    for (Order order : orders) {      order.serve();      orders.remove(order);        }  }  String report() {    return "\ntotal CoffeeFlavour objects made: "        + menu.totalCoffeeFlavoursMade();  }  public static void main(String[] args) {    CoffeeShop shop = new CoffeeShop();    shop.takeOrder("Cappuccino", 2);    shop.takeOrder("Frappe", 1);    shop.takeOrder("Espresso", 1);    shop.takeOrder("Frappe", 897);    shop.takeOrder("Cappuccino", 97);    shop.takeOrder("Frappe", 3);    shop.takeOrder("Espresso", 3);    shop.takeOrder("Cappuccino", 3);    shop.takeOrder("Espresso", 96);    shop.takeOrder("Frappe", 552);    shop.takeOrder("Cappuccino", 121);    shop.takeOrder("Espresso", 121);    shop.service();    System.out.println(shop.report());  }}
0 0