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

**

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

**

  • 案例说明

      享元模式中有几个角色:
      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
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值