跟萌新一起学设计模式(十)之享元模式

it2024-05-14  46

**

设计模式(十)之享元模式

**

案例说明

  享元模式中有几个角色:   1、抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。   2、具体享元(Concrete Flyweight)角色:实现抽象享元角色中所规定的接口。   3、非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。   4、享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

  假设我们开了一家维修小店,小店放有一些维修工具,比如锤子、铁钳、螺丝刀等等。我们小店有几个维修小哥,每次维修时使用工具的时间都极短,按照我们正常的逻辑,一种工具其实我们可以复用,不必每次使用到都要重新买,这时我们就可以考虑使用到享元模式了。

享元模式

  User是非享元角色,里面包含了非共享的外部状态信息uNameTools是抽象享元角色,里面包含了享元方法use(User user),非享元的外部状态以参数的形式通过该方法传入;ConcreteTool是具体的享元角色,包含了共享信息tName,继承了抽象享元角色;ToolBox是享元工厂角色,通过共享信息tName来管理ConcreteTool;维修小哥通过工具箱拿到具体的工具,并使用工具。下面是代码实现:

  抽象的工具类,抽象的享元角色

public abstract class Tools { public abstract void use(User user); }

  具体的工具类,具体的享元角色

@Data public class ConcreteTool extends Tools{ // 内部享元信息 private String tName; public ConcreteTool(String tName){ this.tName = tName; } @Override public void use(User user) { System.out.println("享元信息 " + tName + " 被使用中," + "非享元信息是:" + user.getUName()); } }

  维修小哥实体类,非享元角色

@Data @AllArgsConstructor public class User { // 非共享的外部状态信息 private String uName; }

  工具箱实体类,享元工厂角色

public class ToolBox { // 模拟一个工具箱 private Map<String,Tools> pool = new HashMap<>(); // 根据工具名称拿到工具 public Tools getToolByName(String tName){ if(!pool.containsKey(tName)){ // 没有这种的话就买一个 pool.put(tName,new ConcreteTool(tName)); } return pool.get(tName); } // 返回工具种类的数量 public int getToolCount(){ return pool.size(); } }

  模拟客户端

public class Client { public static void main(String[] args) { ToolBox toolBox = new ToolBox(); Tools tools = null; tools = toolBox.getToolByName("特制大铁锤"); tools.use(new User("王大锤")); tools = toolBox.getToolByName("特制大铁锤"); tools.use(new User("李大锤")); tools = toolBox.getToolByName("特制大铁锤"); tools.use(new User("张大锤")); tools = toolBox.getToolByName("多功能螺丝刀"); tools.use(new User("王一刀")); tools = toolBox.getToolByName("多功能螺丝刀"); tools.use(new User("张三刀")); tools = toolBox.getToolByName("李氏小铁钳"); tools.use(new User("李一钱")); // 看看工具箱里面有几种工具 System.out.println("工具箱里面共有 " + toolBox.getToolCount() + "种 工具"); } }

  测试

D:\jdk8\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\lib\idea_rt.jar=59001:C:\Program Files\JetBrains\IntelliJ IDEA 2019.2\bin" -Dfile.encoding=UTF-8 -classpath D:\jdk8\jre\lib\charsets.jar;D:\jdk8\jre\lib\deploy.jar;D:\jdk8\jre\lib\ext\access-bridge-64.jar;D:\jdk8\jre\lib\ext\cldrdata.jar;D:\jdk8\jre\lib\ext\dnsns.jar;D:\jdk8\jre\lib\ext\jaccess.jar;D:\jdk8\jre\lib\ext\jfxrt.jar;D:\jdk8\jre\lib\ext\localedata.jar;D:\jdk8\jre\lib\ext\nashorn.jar;D:\jdk8\jre\lib\ext\sunec.jar;D:\jdk8\jre\lib\ext\sunjce_provider.jar;D:\jdk8\jre\lib\ext\sunmscapi.jar;D:\jdk8\jre\lib\ext\sunpkcs11.jar;D:\jdk8\jre\lib\ext\zipfs.jar;D:\jdk8\jre\lib\javaws.jar;D:\jdk8\jre\lib\jce.jar;D:\jdk8\jre\lib\jfr.jar;D:\jdk8\jre\lib\jfxswt.jar;D:\jdk8\jre\lib\jsse.jar;D:\jdk8\jre\lib\management-agent.jar;D:\jdk8\jre\lib\plugin.jar;D:\jdk8\jre\lib\resources.jar;D:\jdk8\jre\lib\rt.jar;D:\ideaworkspace\design_pattern\design\target\classes;D:\dev_tools\repository\org\projectlombok\lombok\1.16.10\lombok-1.16.10.jar com.wd.flyweight.Client 享元信息 特制大铁锤 被使用中,非享元信息是:王大锤 享元信息 特制大铁锤 被使用中,非享元信息是:李大锤 享元信息 特制大铁锤 被使用中,非享元信息是:张大锤 享元信息 多功能螺丝刀 被使用中,非享元信息是:王一刀 享元信息 多功能螺丝刀 被使用中,非享元信息是:张三刀 享元信息 李氏小铁钳 被使用中,非享元信息是:李一钱 工具箱里面共有 3种 工具 Process finished with exit code 0 总结   1、在享元模式这样理解,“享”就表示共享,“元”表示对象;   2、系统中有大量对象,这些对象消耗大量内存,并且对象的状态大部分可以外部化时, 我们就可以考虑选用享元模式;   3、用唯一标识码判断,如果在内存中有,则返回这个唯一标识码所标识的对象,用HashMap/HashTable存储;   4、享元模式大大减少了对象的创建,降低了程序内存的占用,提高效率;   5、享元模式提高了系统的复杂度。需要分离出内部状态和外部状态,而外部状态具有固化特性,不应该随着内部状态的改变而改变,这是我们使用享元模式需要注意的地方;   6、使用享元模式时,注意划分内部状态和外部状态,并且需要有一个工厂类加以控制;   7、享元模式经典的应用场景是需要缓冲池的场景,比如 String常量池、数据库连接池;
最新回复(0)