「补课」进行时:设计模式(21)——享元模式

「补课」进行时:设计模式(21)——享元模式

1. 前文汇总

「补课」进行时:设计模式系列

2. 享元模式 2.1 定义

享元模式(Flyweight Pattern)很简单,它解决的需求也很直接,同时它也是池技术的重要实现方式,先看下它的定义:

Use sharing to support large numbers of fine-grained objects efficiently.(使用共享对象可有效地支持大量的细粒度的对象。)

2.2 通用类图

「补课」进行时:设计模式(21)——享元模式

Flyweight 抽象享元角色:它是一个产品的抽象类, 同时定义出对象的外部状态和内部状态的接口或实现。

ConcreteFlyweight 具体享元角色:具体的一个产品类, 实现抽象角色定义的业务。

unsharedConcreteFlyweight 不可共享的享元角色:不存在外部状态或者安全要求(如线程安全) 不能够使用共享技术的对象, 该对象一般不会出现在享元工厂中。

FlyweightFactory 享元工厂:它的职责非常简单, 就是构造一个池容器, 同时提供从池中获得对象的方法。

2.3 通用代码

抽象享元角色:

public abstract class Flyweight { // 内部状态 private String intrinsic; // 外部状态 protected final String extrinsic; // 要求享元角色必须接受外部状态 protected Flyweight(String extrinsic) { this.extrinsic = extrinsic; } // 定义业务操作 abstract void operate(); public String getIntrinsic() { return intrinsic; } public void setIntrinsic(String intrinsic) { this.intrinsic = intrinsic; } }

具体享元角色:

public class ConcreteFlyweight1 extends Flyweight{ protected ConcreteFlyweight1(String extrinsic) { super(extrinsic); } @Override void operate() { } } public class ConcreteFlyweight2 extends Flyweight{ protected ConcreteFlyweight2(String extrinsic) { super(extrinsic); } @Override void operate() { } }

享元工厂:

public class FlyweightFactory { // 定义一个池容器 private static HashMap<String,Flyweight> pool = new HashMap<>(); // 享元工厂 public static Flyweight getFlyweight(String Extrinsic) { // 需要返回的对象 Flyweight flyweight = null; // 在池中没有该对象 if(pool.containsKey(Extrinsic)) { flyweight = pool.get(Extrinsic); } else { // 根据外部状态创建享元对象 flyweight = new ConcreteFlyweight1(Extrinsic); // 放置到池中 pool.put(Extrinsic, flyweight); } return flyweight; } } 2.4 优缺点

享元模式是一个非常简单的模式, 它可以大大减少应用程序创建的对象, 降低程序内存的占用, 增强程序的性能, 但它同时也提高了系统复杂性, 需要分离出外部状态和内部状态, 而且外部状态具有固化特性, 不应该随内部状态改变而改变, 否则导致系统的逻辑混乱。

3. 一个小例子

享元模式很简单,上面的通用代码其实就是一个很好的示例,类似于 Java 中的 String 常量池,没有的对象创建后存在池中,若池中存在该对象则直接从池中取出。

我这里还是再举一个简单的例子,比如接了我一个小型的外包项目,是做一个产品展示网站,后来他的朋友们也希望做这样的网站,但要求都有些不同,我们当然不能直接复制粘贴再来一份,有人希望是视频站,有人希望是图文站等等,而且因为经费原因不能每个网站租用一个空间。

这种事情在生活中很长见,不过大多数情况都是直接 copy 一份代码,再做做改动,但是在享元模式中,就不存在这种情况啦~~~

网站抽象类:

public abstract class WebSite { abstract void use(); }

具体网站类:

public class ConcreteWebSite extends WebSite { private String name; public ConcreteWebSite(String name) { this.name = name; } @Override void use() { System.out.println("网站分类:" + name); } }

网络工厂类:

public class WebSiteFactory { private HashMap<String, WebSite> pool = new HashMap<>(); //获得网站分类 public WebSite getWebSiteCategory(String key) { if(!pool.containsKey(key)) { pool.put(key, new ConcreteWebSite(key)); } return pool.get(key); } //获得网站分类总数 public int getWebSiteCount() { return pool.size(); } }

Client 客户端:

public class Client { public static void main(String[] args) { WebSiteFactory factory = new WebSiteFactory(); WebSite fx = factory.getWebSiteCategory("视频站"); fx.use(); WebSite fy = factory.getWebSiteCategory("视频站"); fy.use(); WebSite fz = factory.getWebSiteCategory("视频站"); fz.use(); WebSite fa = factory.getWebSiteCategory("图文站"); fa.use(); WebSite fb = factory.getWebSiteCategory("图文站"); fb.use(); WebSite fc = factory.getWebSiteCategory("图文站"); fc.use(); System.out.println("网站分类总数为:" + factory.getWebSiteCount()); } }

执行结果:

网站分类:视频站 网站分类:视频站 网站分类:视频站 网站分类:图文站 网站分类:图文站 网站分类:图文站 网站分类总数为:2

可以看出,虽然我们做了 6 个网站,但网站分类只有 2 个。

这样基本算是实现了享元模式的共享对象的目的,但是这里实际上没有体现对象间的不同。

我们再加入一个用户类:

public class User { private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zypsfx.html