本文共 5010 字,大约阅读时间需要 16 分钟。
享元模式(Flyweight)
运用共享技术有效地支持大量细粒度的对象。
让不同的客户透明地使用面向对象的方法操作。
例子:网站
class WebSite{ private String name=""; public WebSite(String name) { this.name=name; } public void Use() { System.out.println("网站分类:"+name); }}public class main{ public static void main(String[] args) { WebSite fx=new WebSite("产品展示");fx.Use(); WebSite fy=new WebSite("产品展示");fy.Use(); WebSite fz=new WebSite("产品展示");fz.Use(); WebSite fl=new WebSite("博客");fl.Use(); WebSite fm=new WebSite("博客");fm.Use(); WebSite fn=new WebSite("博客");fn.Use(); }}
如果要做三个产品展示,三个博客的网站就需要六个网站类的实例,但是本质上都是一样的代码,如果网站增多,实例也就增多,这对服务器资源浪费严重。
解决方法:具体数据和模板可以不同,但核心代码和数据库可以共享。享元对象能做到共享的关键是区分内部状态和外部状态。
如:文本编辑器中通常将每一个字母做成一个享元对象。 享元的内部状态就是这个字母,字母在文本中的位置和子模风格等其他信息则是外部状态 虽然这些字母的位置和字模风格不同,但是所有这些地方使用的都是同一个字母对象。这样,字母对象就可以在整个系统中共享。abstract class Flyweight//Flyweight类,它是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态{ public String intrinsic;//内部状态 protected final String extrinsic;//外部状态 //要求享元角色必须接受外部状态 public Flyweight(String extrinsic) { this.extrinsic=extrinsic; } public abstract void operate(int extrinsic);//定义业务操作 public String getIntrinsic() { return intrinsic; } public void setIntrinsic(String intrinsic) { this.intrinsic = intrinsic; } }class ConcreteFlyweight extends Flyweight//继承并为内部状态增加存储空间{ public ConcreteFlyweight(String extrinsic) {//接受外部状态 super(extrinsic); } //根据外部状态进行逻辑处理 @Override public void operate(int extrinsic) { // TODO Auto-generated method stub System.out.println("具体Flyweight:"+extrinsic); }}class UnsharedConcreteFlyweight extends Flyweight//指不需要共享的Flyweight子类,不强制共享。{ public UnsharedConcreteFlyweight(String extrinsic) { super(extrinsic); } public void operate(int extrinsic) { // TODO Auto-generated method stub System.out.println("不共享的具体Flyweight:"+extrinsic); }}class FlyweightFactory//享元工厂,用来创建并管理Flyweight对象,当用户请求一个Flyweight是,工厂对象提供一个已创建的实例或者创建一个。{ private static HashMappool=new HashMap (); public static Flyweight getFlyweight(String extrinsic) { Flyweight flyweight=null; if(pool.containsKey(extrinsic)) {//池中有该对象 flyweight =pool.get(extrinsic); System.out.print("已有"+extrinsic+"直接从池中取--->"); }else {//根据外部状态创建享元对象 flyweight =new ConcreteFlyweight(extrinsic); pool.put(extrinsic, flyweight);//放入池中 System.out.print("创建"+extrinsic+"并从池中取出--->"); } return flyweight; } }public class main{ public static void main(String[] args) { int extrinsic=22; FlyweightFactory f=new FlyweightFactory(); Flyweight flyweightX=f.getFlyweight("X"); flyweightX.operate(--extrinsic); Flyweight flyweightY=f.getFlyweight("Y"); flyweightY.operate(--extrinsic); Flyweight flyweightZ=f.getFlyweight("Z"); flyweightZ.operate(--extrinsic); Flyweight flyweightRex =f.getFlyweight("X"); flyweightRex.operate(--extrinsic); Flyweight unsharedFlyweight = new UnsharedConcreteFlyweight("X"); unsharedFlyweight.operate(--extrinsic);}}
结果:
创建X并从池中取出--->具体Flyweight:21
创建Y并从池中取出--->具体Flyweight:20 创建Z并从池中取出--->具体Flyweight:19 已有X直接从池中取--->具体Flyweight:18 不共享的具体Flyweight:17
FlyweightFactory根据客户需求返回生成好的对象,但实际上不一定需要事先生成对象的实例,完全可以初始化时什么也不做,到需要时,再去判断对象是否已经存在来决定是否实例化。
UnsharedConcreteFlyweight用来解决不需要共享对象的问题,为什么?因为尽管大部分时间我们都需要共享对象来降低内存的损耗,但个别时候也有可能不需要共享的,那么此时的UnsharedConcreteFlyweight就有存在的必要了,用它去解决那些不惜要共享对象的问题。
内部状态与外部状态
共享网站代码:
class User{//外部状态,用户类 private String name; User(String name) { this.name=name; } public String getName() { return name; } public void setName(String name) { this.name=name; }}abstract class WebSite{ public abstract void Use(User user); }class ConcreteWebSite extends WebSite{ private String name=""; public ConcreteWebSite(String name) { this.name=name; } public void Use(User user) { System.out.println("网站分类:"+name+"用户:"+user.getName()); }}class WebSiteFactory{ //定义一个池容器 private static HashMapflyweights=new HashMap (); //获得网站分类 public WebSite GetWebSiteCategory(String key) { if(!flyweights.containsKey(key)) { WebSite flyweight=new ConcreteWebSite(key); flyweights.put(key, flyweight); } return (flyweights.get(key)); } public int GetWebSiteCount()//获得网站分类总数 { return flyweights.size(); }}public class main{ public static void main(String[] args) { WebSiteFactory f=new WebSiteFactory(); WebSite fx=f.GetWebSiteCategory("产品展示");fx.Use(new User("小菜")); WebSite fy=f.GetWebSiteCategory("产品展示");fy.Use(new User("大鸟")); WebSite fz=f.GetWebSiteCategory("产品展示");fz.Use(new User("娇娇")); WebSite fl=f.GetWebSiteCategory("博客");fl.Use(new User("老顽童")); WebSite fm=f.GetWebSiteCategory("博客");fm.Use(new User("桃谷六仙")); WebSite fn=f.GetWebSiteCategory("博客");fn.Use(new User("南海神鳄")); System.out.println("网站分类总数为"+f.GetWebSiteCount());}}
结果:
网站分类:产品展示用户:小菜
网站分类:产品展示用户:大鸟 网站分类:产品展示用户:娇娇 网站分类:博客用户:老顽童 网站分类:博客用户:桃谷六仙 网站分类:博客用户:南海神鳄 网站分类总数为2
享元模式设计的重点就在于分离变与不变。
把一个对象的状态分成内部状态和外部状态,内部状态是不变的,外部状态是可变的。
然后通过共享不变的部分,达到减少对象数量节约内存。
享元模式应用场合:
享元模式优点:
降低内存中对象的数量,节省内存空间。 缺点: 使得系统更加的复杂。将享元对象外部化,使运行时间变长,逻辑变得相当复杂。转载地址:http://xxyzi.baihongyu.com/