运用共享技术有效地支持大量的细粒度的对象。
以下场景适用享元模式:
- 一个应用程序适用了大量的对象。
- 完全由于使用大量的对象,造成很大的存储开销。
- 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
示例1:
public interface BMWCar { double calculatePrice(BMWCarCustomisation custom); void printFullCharacteristics(BMWCarCustomisation custom); }
public interface BMWCarCustomisation { // customize Tire size int getTireSize(); String getLaserSignature(); // a lot of customisation attributes can be in there for a BMW car void printCustomisations(); }
public interface BMWCarFactory { BMWCar createCar(); }
public interface BMWCarFlyWeightFactory { enum Model {Serie1, Serie2, Serie3}; BMWCar getBMWModel(Model m); }
public class BMWSerie1 implements BMWCar { private final static double BASE_PRICE = 25000; @Override public double calculatePrice(BMWCarCustomisation custom) { return BASE_PRICE + getSpecificSerie1PriceBasedOnCustom(custom) + getExportationTaxe(custom); } @Override public void printFullCharacteristics(BMWCarCustomisation custom) { // print all BMW 1 Series specific characteristics // (codes in there) custom.printCustomisations(); // print details based on these customisations } private double getSpecificSerie1PriceBasedOnCustom(BMWCarCustomisation custom) { // (e.g., calculation based on custom specific to Series 1) double sum = 0; if (custom.getTireSize() == 19) { sum += 1200; } else { sum += 2100; } return sum; } private double getExportationTaxe(BMWCarCustomisation custom) { // (calculation based on custom exportation taxes only for this model) double sum = 0; if (!custom.getLaserSignature().isEmpty()) { sum += 987; } return sum; } }
public class BMWSerie1Factory implements BMWCarFactory { @Override public BMWCar createCar() { return new BMWSerie1(); } }
public class BMWSerie2 implements BMWCar { private final static double BASE_PRICE = 28000; @Override public double calculatePrice(BMWCarCustomisation custom) { return BASE_PRICE + getSpecificSerie2PriceBasedOnCustom(custom); } @Override public void printFullCharacteristics(BMWCarCustomisation custom) { // print all BMW 2 Series specific characteristics // (codes in there) custom.printCustomisations(); // print details based on these customisations } private double getSpecificSerie2PriceBasedOnCustom(BMWCarCustomisation custom) { // (e.g., calculation based on custom specific to Series 2) double sum = 0; if (custom.getTireSize() == 19) { sum += 2000; } else { sum += 3000; } if (!custom.getLaserSignature().isEmpty()) { if (custom.getLaserSignature().length() > 10) { sum += 1200; } else { sum += 400; } } return sum; } }
public class BMWSerie2Factory implements BMWCarFactory { @Override public BMWCar createCar() { return new BMWSerie2(); } }
public class BMWSerieCarCustomisation implements BMWCarCustomisation { private int tireSize; private String laserSignature; public BMWSerieCarCustomisation(int tireSize, String laserSignature) { this.tireSize = tireSize; this.laserSignature = laserSignature; } public int getTireSize() { return tireSize; } public String getLaserSignature() { return laserSignature; } @Override public void printCustomisations() { System.out.println("Tire Size:" + getTireSize()); System.out.println("LaserSignature:" + getLaserSignature()); System.out.println("LaserSignature Size:" + getLaserSignature().length()); } }
public class BMWSerieFlyWeightFactory implements BMWCarFlyWeightFactory { private Map<Model, BMWCar> cache = new HashMap<>(); public synchronized BMWCar getBMWModel(Model m) { if (!cache.containsKey(m)) { BMWCarFactory concreteFactory; switch (m) { case Serie2: concreteFactory = new BMWSerie2Factory(); break; /* case Serie3: concreteFactory = new BMWSerie3Factory(); break; */ /* * Just code to have a hint ! */ default: concreteFactory = new BMWSerie1Factory(); break; } cache.put(m, concreteFactory.createCar()); } return cache.get(m); } }
public class MainTest { public static void main(String[] args) { BMWCarFlyWeightFactory factory = new BMWSerieFlyWeightFactory(); BMWCar serie1Car = factory.getBMWModel(BMWCarFlyWeightFactory.Model.Serie1); BMWCar serie1Car2 = factory.getBMWModel(BMWCarFlyWeightFactory.Model.Serie1); System.out.println("check for Object for Serie1:" + (serie1Car == serie1Car2)); BMWCar serie2Car = factory.getBMWModel(BMWCarFlyWeightFactory.Model.Serie2); BMWCar serie2Car2 = factory.getBMWModel(BMWCarFlyWeightFactory.Model.Serie2); System.out.println("check for Object for Serie2:" + (serie2Car == serie2Car2)); BMWCarCustomisation custom1 = new BMWSerieCarCustomisation(19, "Oh yeah"); BMWCarCustomisation custom2 = new BMWSerieCarCustomisation(21, "For bob"); BMWCarCustomisation custom3 = new BMWSerieCarCustomisation(26, "give it a ride !!"); // BMW 1 Series System.out.println("BMW Serie1 + Custom1 Price:\nFull Price:" + serie1Car.calculatePrice(custom1)); serie1Car.printFullCharacteristics(custom1); System.out.println("BMW Serie1 + Custom2 Price:\nFull Price:" + serie1Car.calculatePrice(custom2)); serie1Car.printFullCharacteristics(custom2); System.out.println("BMW Serie1 + Custom3 Price:\nFull Price:" + serie1Car.calculatePrice(custom3)); serie1Car.printFullCharacteristics(custom3); /// It's the samed BMW 1 Series Flyweight instance; the variant part is provided /// by the operation and customs // BMW 2 Series System.out.println("BMW Serie2 + Custom1 Price:\nFull Price:" + serie2Car.calculatePrice(custom1)); serie2Car.printFullCharacteristics(custom1); System.out.println("BMW Serie2 + Custom2 Price:\nFull Price:" + serie2Car.calculatePrice(custom2)); serie2Car.printFullCharacteristics(custom2); System.out.println("BMW Serie2 + Custom3 Price:\nFull Price:" + serie2Car.calculatePrice(custom3)); serie2Car.printFullCharacteristics(custom3); /// It's the samed BMW 2 Series Flyweight instance; the variant part is provided /// by the operation and customs } }
示例2:
public interface Potion { void drink(); }
public class PoisonPotion implements Potion { @Override public void drink() { System.out.println("Urgh! This is poisonous. (Potion="+System.identityHashCode(this)+")" ); } }
public enum PotionType { HEALING, INVISIBILITY, STRENGTH, HOLY_WATER, POISON }
public class HealingPotion implements Potion { @Override public void drink() { System.out.println("You feel healed. (Potion="+System.identityHashCode(this)+")"); } }
public class HolyWaterPotion implements Potion { @Override public void drink() { System.out.println("You feel blessed. (Potion={"+System.identityHashCode(this)+"})" ); } }
public class InvisibilityPotion implements Potion { @Override public void drink() { System.out.println("You become invisible. (Potion="+System.identityHashCode(this)+")" ); } }
public class StrengthPotion implements Potion { @Override public void drink() { System.out.println("You feel strong. (Potion="+System.identityHashCode(this)+")" ); } }
public class PotionFactory { private final Map<PotionType, Potion> potions; public PotionFactory() { potions = new EnumMap<>(PotionType.class); } Potion createPotion(PotionType type) { Potion potion = potions.get(type); if (potion == null) { switch (type) { case HEALING: potion = new HealingPotion(); potions.put(type, potion); break; case HOLY_WATER: potion = new HolyWaterPotion(); potions.put(type, potion); break; case INVISIBILITY: potion = new InvisibilityPotion(); potions.put(type, potion); break; case POISON: potion = new PoisonPotion(); potions.put(type, potion); break; case STRENGTH: potion = new StrengthPotion(); potions.put(type, potion); break; default: break; } } return potion; } }
public class AlchemistShop { private List<Potion> topShelf; private List<Potion> bottomShelf; /** * Constructor */ public AlchemistShop() { topShelf = new ArrayList<>(); bottomShelf = new ArrayList<>(); fillShelves(); } private void fillShelves() { PotionFactory factory = new PotionFactory(); topShelf.add(factory.createPotion(PotionType.INVISIBILITY)); topShelf.add(factory.createPotion(PotionType.INVISIBILITY)); topShelf.add(factory.createPotion(PotionType.STRENGTH)); topShelf.add(factory.createPotion(PotionType.HEALING)); topShelf.add(factory.createPotion(PotionType.INVISIBILITY)); topShelf.add(factory.createPotion(PotionType.STRENGTH)); topShelf.add(factory.createPotion(PotionType.HEALING)); topShelf.add(factory.createPotion(PotionType.HEALING)); bottomShelf.add(factory.createPotion(PotionType.POISON)); bottomShelf.add(factory.createPotion(PotionType.POISON)); bottomShelf.add(factory.createPotion(PotionType.POISON)); bottomShelf.add(factory.createPotion(PotionType.HOLY_WATER)); bottomShelf.add(factory.createPotion(PotionType.HOLY_WATER)); } /** * Get a read-only list of all the items on the top shelf * * @return The top shelf potions */ public final List<Potion> getTopShelf() { return Collections.unmodifiableList(this.topShelf); } /** * Get a read-only list of all the items on the bottom shelf * * @return The bottom shelf potions */ public final List<Potion> getBottomShelf() { return Collections.unmodifiableList(this.bottomShelf); } /** * Enumerate potions */ public void enumerate() { System.out.println("Enumerating top shelf potions"); for (Potion p : topShelf) { p.drink(); } System.out.println("Enumerating bottom shelf potions"); for (Potion p : bottomShelf) { p.drink(); } } }
public class App { /** * Program entry point * * @param args command line args */ public static void main(String[] args) { AlchemistShop alchemistShop = new AlchemistShop(); alchemistShop.enumerate(); } }
架构师成长营