人物:大鸟,小菜
事件:小菜最近接了点私活,是一个做网站的外包,刚开始是为一个客户做,后来另一个客户也需要做一个类似的网站,后面客户多了这样代码虽然结构类似但是多多少少都有些不一样了,而且很费租用空间,后期更是难以维护,在小菜给大鸟倾诉完之后,大鸟为小菜提供了一种新的设计模式:享元模式
享元模式:
1.用代码设计小菜实例
2.了解共享模式
3.通过共享模式改进小菜实例并小结
每个网站一个实例的设计实现
WebSite类,网站:
@Slf4j public class WebSite { private String name = ""; public WebSite(String name) { this.name = name; } public void use() { log.info("网站分类:" + name); } }
客户端代码:
public class WebSiteClient { 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(); } }
小菜:这样就做出3个产品展示,3个博客的网站
享元模式
1.概念:运用共享技术有效地支持大量细粒度的对象
2.结构图:
3.代码示例:
Flyweight类,是所有具体享元类的超类或接口
public abstract class Flyweight { public abstract void Operation(int extrinsicstate); }
ConcreteFlyweight类,为内部状态增加存储空间:
@Slf4j public class ConcreteFlyweight extends Flyweight { @Override public void Operation(int extrinsicstate) { log.info("具体Flyweight: " + extrinsicstate); } }
UnsharedConcreteFlyweight类,指那些不需要共享的Flyweight子类:
@Slf4j public class UnsharedConcreteFlyweight extends Flyweight { @Override public void Operation(int extrinsicstate) { log.info("不共享的具体Flyweight: " + extrinsicstate); } }
FlyweightFactory类,是一个享元工厂,用来创建和管理FlyweightFactory,主要是确保合理共享Flyweight:
public class FlyweightFactory { private Hashtable flyweights = new Hashtable<>(); public FlyweightFactory() { flyweights.put("X", new ConcreteFlyweight()); flyweights.put("Y", new ConcreteFlyweight()); flyweights.put("Z", new ConcreteFlyweight()); } public Flyweight getFlyweight(String key) { return (Flyweight)flyweights.get(key); } }
客户端代码:
public class WebSiteClient { public static void main(String[] args) { int extrinsicstate = 22; FlyweightFactory f = new FlyweightFactory(); Flyweight fx = f.getFlyweight("X"); fx.Operation(--extrinsicstate); Flyweight fy = f.getFlyweight("Y"); fy.Operation(--extrinsicstate); Flyweight fz = f.getFlyweight("Z"); fz.Operation(--extrinsicstate); UnsharedConcreteFlyweight uf = new UnsharedConcreteFlyweight(); uf.Operation(--extrinsicstate); } }
享元模式结合小菜实例
网站抽象类:
@Slf4j public abstract class WebSite { public abstract void use(); }
具体网站类:
@Slf4j public class ConcreteWebSite extends WebSite { private String name = ""; public ConcreteWebSite(String name) { this.name = name; } @Override public void use() { log.info("网站分类:" + name); } }
网站工厂类:
public class WebSiteFactory { private Hashtable flyweights = new Hashtable(); public WebSite getWebSiteCategory(String key) { if (!flyweights.containsKey(key)) { flyweights.put(key, new ConcreteWebSite(key)); } return (WebSite) flyweights.get(key); } public int getWebSiteCount() { return flyweights.size(); } }
客户端代码:
public class WebSiteClient { public static void main(String[] args) { WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.getWebSiteCategory("产品展示"); fx.use(); WebSite fy = f.getWebSiteCategory("产品展示"); fy.use(); WebSite fz = f.getWebSiteCategory("产品展示"); fz.use(); WebSite fl = f.getWebSiteCategory("博客"); fl.use(); WebSite fm = f.getWebSiteCategory("博客"); fm.use(); WebSite fn = f.getWebSiteCategory("博客"); fn.use(); } }
最后输出的结果:
网站分类:产品展示
网站分类:产品展示
网站分类:产品展示
网站分类:博客
网站分类:博客
网站分类:博客
网站分类总数为2
大鸟:这样算是基本实现了享元模式共享对象的目的,不管建几个网站,只要key相同,那么就一样,这里只体现了相同的部分,但实际中不同企业可能需要的网站功能同,但是不同公司的账号,数据都是不同的,那你有考虑过怎么处理么,我再给你讲讲享元模式的内部状态和外部状态。
享元模式的内部状态和外部状态
享元模式可以避免大量相似类的开销。在程序设计中,有时需要生成大量细粒度的类实例来表示数据,如果能发现这些实例除了几个参数外,基本都是相同的,如果能把参数移到类实例的外面,在方法调用时将它们传进来,就可以通过共享大幅度减少单个实例的数目。
也就是说客户的状态就是外部状态,应该由专门的对象来处理。
于是小菜出了第三版:
1.代码结构图:
2.代码示例:
User类,用户类,用户网站的客户账号:
@Data @Accessors(chain = true) public class User { private String name; }
网站抽象类:
@Slf4j public abstract class WebSite {
//使用的方法需要传递用户对象 public abstract void use(User user); }
网站工厂类:
public class WebSiteFactory { private Hashtable flyweights = new Hashtable(); public WebSite getWebSiteCategory(String key) { if (!flyweights.containsKey(key)) { flyweights.put(key, new ConcreteWebSite(key)); } return (WebSite) flyweights.get(key); } public int getWebSiteCount() { return flyweights.size(); } }
客户端代码:
@Slf4j public class WebSiteClient { public static void main(String[] args) { WebSiteFactory f = new WebSiteFactory(); WebSite fx = f.getWebSiteCategory("产品展示"); User user1 = new User().setName("小菜"); fx.use(user1); WebSite fy = f.getWebSiteCategory("产品展示"); User user2 = new User().setName("大鸟"); fx.use(user2); WebSite fz = f.getWebSiteCategory("产品展示"); User user3 = new User().setName("娇娇"); fz.use(user3); WebSite fl = f.getWebSiteCategory("博客"); User user4 = new User().setName("老顽童"); fl.use(user4); WebSite fm = f.getWebSiteCategory("博客"); User user5 = new User().setName("桃谷六仙"); fm.use(user5); WebSite fn = f.getWebSiteCategory("博客"); User user6 = new User().setName("南海鳄神"); fn.use(user6); log.info("网站分类总数为{}", f.getWebSiteCount()); } }
结果输出:
网站分类:产品展示用户:小菜
网站分类:产品展示用户:大鸟
网站分类:产品展示用户:娇娇
网站分类:博客用户:老顽童
网站分类:博客用户:桃谷六仙
网站分类:博客用户:南海鳄神
网站分类总数为2
3.享元模式的应用场景
(1)理解:当一个应用程序使用了大量重复的对象,而这些大量的存储对象造成了很大开销时,享元模式就可以通过共享对象来避免创建过多对象。
(2)举例:String常量池、数据库连接池、缓冲池等等,或者你要开发一款五子棋游戏,理论上一盘棋有361个空格要创建361个对象,但用了共享模式后,只用创建两个即可。
(3)优点:减少了大量重复的代码,简化了代码的复杂的,而且减小了开销,节省了内存,提高了性能。