享元模式的思考
程序员文章站
2022-05-05 08:23:39
...
先看维基的解释
享元模式(英语:Flyweight Pattern)是一种软件设计模式。它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。
我觉得FlyWeight的独特之处首先在于它的出发点,与其它模式不同,不是为了OCP啦,解耦啦等等,它是一个很现实的理由:节约内存。
它实现的手段也很简单,根据场景需求,将巨量对象的相对不变的特性与可变的特性抽离,称之为内蕴与外蕴,或者其它叫法,外在内在什么,反正就是这么个意思。然后看内蕴情况建立一些模板对象,把不同的外蕴传入,使之看上去有n多实例在活动,其实来来去去就这么几个"模板"对象。
当然节约内存也不是没有代价了,我认为加载外蕴所花时间倒是其次,主要一点:无法定位到具体的实例,因为其实这些都是"假象"。这个就是很大的限制了。
网上有些享元模式例子,基本上都是字符处理和图形处理,换个口味我也来练习一把
package flyWeight; public interface IFlyWeight { //外蕴传入 public void name(String name); // public void say(); }
接口,name()模拟外蕴传入
public class Person implements IFlyWeight { //模拟内蕴,相对不会变化 private final String sayProperty = "你好"; private final String category = "人类"; private String name; public String getName() { return name; } public String getSayProperty() { return sayProperty; } public String getCategory() { return category; } @Override public void say() { System.out.println(sayProperty + " 我是" + this.name + " 我是" + this.category); } @Override public void name(String name) { this.name = name; } }
一个实现类Person,享元模式中的ConcreteFlyWeight角色
public class Bird implements IFlyWeight { private final String sayProperty = "叽叽喳喳"; private final String category = "鸟类"; private String name; public String getCatagory() { return getCatagory(); } public String getName() { return name; } @Override public void say() { System.out.println(sayProperty + " 我叫" + this.name + " 我是" + this.category); } @Override public void name(String name) { this.name = name; } }
另一个实现类
public class Family implements IFlyWeight { private HashMap<String,IFlyWeight> map = new HashMap<String,IFlyWeight>(); public void add(String name,IFlyWeight flyWeight){ map.put(name, flyWeight); } @Override public void name(String name) { } @Override public void say() { Iterator<Entry<String, IFlyWeight>> it = map.entrySet().iterator(); while(it.hasNext()){ Map.Entry<String, IFlyWeight> entry = it.next(); String name = entry.getKey(); IFlyWeight flyWeight = entry.getValue(); flyWeight.name(name); flyWeight.say(); } } }
这个实现类有点不一样,用到Composite模式,持有一个享元的聚合。
import java.util.HashMap; public class FlyWeightFactory { private HashMap<String,IFlyWeight> hp = new HashMap<String, IFlyWeight>(); IFlyWeight flyWeight; public IFlyWeight getLife(String category) { flyWeight = (IFlyWeight) hp.get(category); if (flyWeight == null) { if (category.equals("人类")) { flyWeight = new Person(); hp.put(category, flyWeight); } else if (category.equals("鸟类")) { flyWeight = new Bird(); hp.put(category, flyWeight); } } return flyWeight; } }
享元工厂FlyWeightFactory,管理并提供享元实例,就是那些"模板"实例
public class Client { private static FlyWeightFactory factory = new FlyWeightFactory(); private static IFlyWeight flyWeight; public static void main(String[] args) { //人 for(int i=0;i<=2;i++){ flyWeight = factory.getLife("人类"); flyWeight.name(String.valueOf(i)); flyWeight.say(); } System.out.println(""); //鸟 for(int i=0;i<=2;i++){ flyWeight = factory.getLife("鸟类"); flyWeight.name(String.valueOf(i)); flyWeight.say(); } System.out.println(""); //家 Family family = new Family(); family.add("女主人",factory.getLife("人类")); family.add("男主人",factory.getLife("人类")); family.add("爱家的鸟",factory.getLife("鸟类")); family.say(); } }
写个客户端测试一下
这里是输出结果:
你好 我是0 我是人类 你好 我是1 我是人类 你好 我是2 我是人类 叽叽喳喳 我叫0 我是鸟类 叽叽喳喳 我叫1 我是鸟类 叽叽喳喳 我叫2 我是鸟类 叽叽喳喳 我叫爱家的鸟 我是鸟类 你好 我是女主人 我是人类 你好 我是男主人 我是人类
来来回回就2个实例在演戏,看上去却貌似很多,是不是觉得有点无聊呵呵
结束语:一群大雁在天上飞,一会排成S形,一会排成B形,定睛一看,其实天上就一只大雁!