/*** 网站类*/
public class WebSite {private String name = "";public WebSite(String name) {this.name = name;}public void use() {System.out.println("网站分类:"+name);}
}
public class Client {public static void main(String[] args) {WebSite webSite1 = new WebSite("产品展示");webSite1.use();WebSite webSite2 = new WebSite("产品展示");webSite2.use();WebSite webSite3 = new WebSite("产品展示");webSite3.use();WebSite webSite4 = new WebSite("博客");webSite4.use();WebSite webSite5 = new WebSite("博客");webSite5.use();WebSite webSite6 = new WebSite("博客");webSite6.use();}
}
享元模式:运用共享技术有效地支持大量细粒度的对象。
Flyweight类,它是所有具体享元类的超类或接口,通过这个接口,Flyweight可以接受并作用于外部状态。
public abstract class Flyweight {public abstract void operation(int extrinsicstate);
}
ConcreteFlyweight类是继承Flyweight超类或实现Flyweight接口,并为内部状态增加存储空间。
public class ConcreteFlyweight extends Flyweight {public void operation(int extrinsicstate) {System.out.println("具体Flyweight:" + extrinsicstate);}
}
UnsharedConcreteFlyweight是指那些不需要共享的Flyweight子类,因为Flyweight接口共享成为可能,但它并不强制共享。
public class UnsharedConcreteFlyweight extends Flyweight {public void operation(int extrinsicstate) {System.out.println("不共享具体的Flyweight:" + extrinsicstate);}
}
FlyweightFactory是一个享元工厂,用来创建并管理Flyweight对象。它主要是用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话)。
public class FlyweightFactory {private Map<String,Object> flyweights = new HashMap<String,Object>();// 初始化工厂时,先生成3个实例// 并不是一定需要事先生成对象实例,可以初始化时什么也不做,到需要时,再去判断对象是否为null来决定是否实例化public FlyweightFactory() {flyweights.put("X", new ConcreteFlyweight());flyweights.put("Y", new ConcreteFlyweight());flyweights.put("Z", new ConcreteFlyweight());}// 根据客户端请求,获得已生成的实例public Flyweight getFlyweight(String key) {return (Flyweight) (key);}
}
public class Client {public static void main(String[] args) {int extrinsicstate = 22; // 代码外部状态FlyweightFactory factory = new FlyweightFactory();Flyweight fx = Flyweight("X");fx.operation(--extrinsicstate);Flyweight fy = Flyweight("Y");fy.operation(--extrinsicstate);Flyweight fz = Flyweight("Z");fz.operation(--extrinsicstate);Flyweight uf = new UnsharedConcreteFlyweight();uf.operation(--extrinsicstate);}
}
/*** 网站抽象类*/
public abstract class WebSite {public abstract void use();
}
/*** 具体网站类*/
public class ConcreteWebSite extends WebSite {private String name = "";public ConcreteWebSite(String name) {this.name = name;}@Overridepublic void use() {System.out.println("网站分类:" + name);}
}
/*** 网站工厂类*/
public class WebSiteFactory {private Map<String,Object> flyweights = new HashMap<String,Object>();// 获得网站分类public WebSite getWebSiteCategory(String key) {// 判断是否存在这个对象,如果存在,则直接返回,若不存在,则实例化它再返回if(!ainsKey(key)) {flyweights.put(key, new ConcreteWebSite(key));}return (WebSite) (key);}// 获得网站分类总数public int getWebSiteCount() {return flyweights.size();}
}
public class Client {public static void main(String[] args) {WebSiteFactory factory = new WebSiteFactory();// 实例化“产品展示”的“网站”对象WebSite fx = WebSiteCategory("产品展示");fx.use();// 共享上方生成的对象,不再实例化WebSite fy = WebSiteCategory("产品展示");fy.use();WebSite fz = WebSiteCategory("产品展示");fz.use();WebSite fl = WebSiteCategory("博客");fl.use();WebSite fm = WebSiteCategory("博客");fm.use();WebSite fn = WebSiteCategory("博客");fn.use();// 统计实例化个数,结果应该为2System.out.println("网站分类总数 " + WebSiteCount());}
}
在享元对象内部并且不会随环境改变而改变的共享部分,可以称为是享元对象的内部状态,而随环境改变而改变的、不可以共享的状态就是外部状态了。
事实上,享元模式可以避免大量非常相似类的开销。在程序设计中,有时需要生成大量细粒度的类来表示数据。如果能发现这些实例除了几个参数外基本上都是相同的,有时就能够受大幅度地减少需要实例化的类的数量。如果能把那些参数移到类实例的外面,在方法调用时将它们传递进来,就可以通过共享大幅度地减少单个实例的数目。
也就是说,享元模式Flyweight执行时所需的状态是有内部的也可能有外部的,内部状态存储于ConcreteFlyweight对象之中,而外部对象则应该考虑由客户端对象存储或计算,当调用Flyweight对象的操作时,将该状态传递给它。
用户类,用于网站的客户账号,是“网站”类的外部状态。
public class User {private String name;public User(String name) {this.name = name;}public String getName() {return name;}}
public abstract class WebSite {// "使用"方法需要传递“用户”对象public abstract void use(User user);
}
public class ConcreteWebSite extends WebSite {private String name = "";public ConcreteWebSite(String name) {this.name = name;}@Overridepublic void use(User user) {System.out.println("网站分类:" + name + " 用户:"Name());}}
public class WebSiteFactory {private Map<String,Object> flyweights = new HashMap<String,Object>();// 获得网站分类public WebSite getWebSiteCategory(String key) {if(!ainsKey(key)) {flyweights.put(key, new ConcreteWebSite(key));}return (WebSite) (key);}// 获得网站分类总数public int getWebSiteCount() {return flyweights.size();}
}
public class Client {public static void main(String[] args) {WebSiteFactory factory = new WebSiteFactory();WebSite fx = WebSiteCategory("产品展示");fx.use(new User("张无忌"));WebSite fy = WebSiteCategory("产品展示");fy.use(new User("杨过"));WebSite fz = WebSiteCategory("产品展示");fz.use(new User("小龙女"));WebSite fl = WebSiteCategory("博客");fl.use(new User("黄药师"));WebSite fm = WebSiteCategory("博客");fm.use(new User("老顽童"));WebSite fn = WebSiteCategory("博客");fn.use(new User("段正淳"));System.out.println("网站分类总数 " + WebSiteCount());}
如果一个应用程序使用了大量的对象,而大量的这些对象造成了很大的存储开销时就应该考虑使用;
还有就是对象的大多数状态可以是外部状态,如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象,此时可以考虑使用享元模式。
因为用了享元模式,所以有了共享对象,实例总数就大大减少了,如果共享的对象越多,存储节约也就越多,节约量随着共享状态的增多而增大。
String中就用了享元模式。
享元模式更多的时候是一种底层的设计模式。
围棋、五子棋中,颜色是棋子的内部状态,而方位坐标是棋子的外部状态。围棋361个空位放棋子,不是每盘棋都产生两三百个棋子对象,不然服务器很难支持更多的玩家玩围棋游戏了,因为内存有限。如果用享元模式,棋子对象可以减少到只有两个。
在某些情况下,对象的数量可能会太多,从而导致了运行时的资源与性能损耗。那么我们如何去避免大量细粒度的对象,同时又不影响客户程序,是一个值得去思考的问题,享元模式,可以运用共享技术有效地支持大量细粒度的对象。不过,使用享元模式需要维护一个记录了系统已有的所有享元的列表,而这本身需要耗费资源,另外享元模式使得系统更加复杂。为了使对象可以共享,需要将一些状态外部化,这使得程序的逻辑复杂化。因此,应当在有足够多的对象实例可供共享时才值得使用享元模式。
注:本文内容源自程杰的《大话设计模式》
本文发布于:2024-02-01 09:36:50,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170675141235704.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |