前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式-享元模式

设计模式-享元模式

作者头像
逍遥壮士
发布2020-09-18 15:06:45
3140
发布2020-09-18 15:06:45
举报
文章被收录于专栏:技术趋势技术趋势

背景

夏天降温,各家各户使用降温神器各不一样,有的用风扇,有的用冷风扇,有的用空调,牛逼的直接有中央空调(有钱,真有钱~),重点是要用,如果没有想用那装一个,下次直用就就OK了,而一般一个房间装一台就OK,不用重复装多台(你家里有钱除外),每次就直接使用,享元模式就是解决这种重复。

享元模式是什么?

定义:享元模式(Flyweight Pattern)属于结构型模式一种,主要用于大量减少创建对象的数量,以减少内存占用和提高性能。它提供了减少对象数量从而改善应用所需的对象结构的式,但是提高了系统的复杂性,需要享元模式分享出内部状态和外部状态,而且外部状态是固有特性,内部状态是随系统改变而改变,一般享元模式+工厂模式+单例模式一起使用。

内部状态:对象内部的信息,不会随着环境改变而改变,可以共享的状态,比如的id

外部状态:对象依赖的一个标记,随着环境改变而改变的,可以共享的状态,比如昵称

享元角色

Flyweight:抽象享元类,通过这个类传入外部状态并作用于外部状态;

ConcreteFlyweight:具体享元类,具体的享元实现对象,必须是可共享的,需要封装享元对象的内部状态;

UnsharedConcreteFlyweight:非分享具体享元类,非共享的享元实现对象,并不是所有的享元对象都可以共享,非共享的享元对象通常是享元对象的组合对象;

FlyweightFactory:享元工厂类,主要用来创建并管理共享的享元对象,并对外提供访问共享享元的接口;

享元模式可以干嘛?

理解为一个家(共享池),降温工具(电器),有就用,没有就添加(创建),然后放到家(共享池)里面,下次用到直接用就可以了。享元就是家里不用重复装空调,一般一个房间一个就够了,将家抽象为一个池子,而各种降温家电为抽象享元类,空调、风扇等具体对象为具体享元类,放置这些家电的地方,墙上、地板等(工厂),而这些家电,电器名称为(内部状态),电器档数(外部状态)。

优点:

减少系统资源开销,减少了频繁创建对象,可以节省内存中的对象数量;

缺点:

增加系统复杂度,因为需要将一些内部元素共享出来,所以导致逻辑更加复杂;

可能造成线程安全,单纯的享元模式是在高并发场景下存在线程安全的,所以在创建对象的时候最好享元+单例一起使用。

享元模式类图

源码下载:https://gitee.com/hong99/design-model/issues/I1IMES

实现代码

代码语言:javascript
复制
/**
 * @Auther: csh
 * @Date: 2020/6/1 17:33
 * @Description:降温工具抽象(抽象享元类)
 */
public  interface ICoolingTool {
    //工具
    void useTool();
}
代码语言:javascript
复制
/**
 * @Auther: csh
 * @Date: 2020/6/1 17:36
 * @Description:家电(具体享元角色类)
 */
public class ElectricTool implements ICoolingTool {
    //电器名称
    private String name;
    //档数
    private int number;


    public ElectricTool(String name) {
        this.name = name;
    }
    @Override
    public void useTool() {
        System.out.println("启动了"+name+"开始降温!开了"+number+"档");
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }
}
代码语言:javascript
复制
/**
 * @Auther: csh
 * @Date: 2020/6/1 17:38
 * @Description:电器工厂(享元工厂角色类)
 */
public class ElectricToolFactory {
    private static final HashMap<String,ICoolingTool> pool = new HashMap <String, ICoolingTool>();

    public static ICoolingTool getCoolingTool(String electricName){
        ICoolingTool tool = pool.get(electricName);
            //双重校验
            synchronized (ElectricToolFactory.class){
                if(null==tool){
                    synchronized (ElectricToolFactory.class){
                        //没有就添加家电
                        tool = new ElectricTool(electricName);
                        pool.put(electricName,tool);
                        System.out.println("家里新添了家电"+electricName);
                    }
                }
            }
            return tool;
    }
}
代码语言:javascript
复制
/**
 * @Auther: csh
 * @Date: 2020/6/1 17:50
 * @Description:
 * 该例,理解为一个家(共享池),降温工具(电器),有就用,没有就添加(创建),然后放到家(共享池)里面,下次用到直接用就可以了。享元就是家里不用重复装空调,一般一个房间一个就够了,总不可能一直加嘛。将家抽象为一个池子,而各种降温家电为抽象享元类,空调、风扇等具体对象为具体享元类,放置这些家电的地方,墙上、地板等(工厂),而这些家电,电器名称为(内部状态),电器档数(外部状态)。
 * 演示
 */
public class Client {
    private static final String[] homeElectricityTool = { "风扇", "冷风扇", "空调", "中央空调" };
    public static void main(String[] args) {
        for(int i=0;i<20;i++){
            ElectricTool tool = (ElectricTool)ElectricToolFactory.getCoolingTool(getRandomElectrici());
            tool.setNumber(getRandomNumber());
            tool.useTool();
        }
        //String中也是使用了享元模式进行储存,内存同样引用同一个地址
        String str1 = "123456";
        String str2 = "123456";
        System.out.println(str1==str2);
        System.out.println(str1.hashCode());
        System.out.println(str2.hashCode());
    }

    private static String getRandomElectrici() {
        return homeElectricityTool[(int)(Math.random()*homeElectricityTool.length)];
    }

    private static int getRandomNumber() {
        return (int)(Math.random()*6 );
    }
}

结果

代码语言:javascript
复制
家里新添了家电冷风扇
启动了冷风扇开始降温!开了2档
家里新添了家电风扇
启动了风扇开始降温!开了3档
启动了风扇开始降温!开了1档
家里新添了家电中央空调
启动了中央空调开始降温!开了5档
启动了中央空调开始降温!开了3档
启动了风扇开始降温!开了5档
家里新添了家电空调
启动了空调开始降温!开了1档
启动了中央空调开始降温!开了3档
启动了中央空调开始降温!开了0档
启动了空调开始降温!开了1档
启动了中央空调开始降温!开了4档
启动了风扇开始降温!开了5档
启动了空调开始降温!开了2档
启动了风扇开始降温!开了4档
启动了空调开始降温!开了1档
启动了空调开始降温!开了3档
启动了空调开始降温!开了0档
启动了风扇开始降温!开了2档
启动了中央空调开始降温!开了4档
启动了空调开始降温!开了1档
true
1450575459
1450575459

源码下载:https://gitee.com/hong99/design-model/issues/I1IMES总结

享元模式,运用了共享的技术有效的支持大量 细粒度对象的复用,解决同一类型/对象重复创建,导致系统内存不足性能问题,而产生的一个设计模式,来减少对象的重复创建,可以实现多次复用,提高系统性能。当然也引发了系统的复杂度提高,业务逻辑更加复杂。享元模式的核心在于通过一个享元工厂,用户每次需要创建对象的时候,首先去享元工厂进行查找,若存在则直接返回给用户,若不存在则创建后放到享元池子中,以便下次使用。当然该模式中的池子,建议在日常开发过程中需要有一个统一的过期时间,或可以设计成多久没有就自动被GC回复,以防由于不断堆积导致内存溢出。当然也推荐使用类似于 redis,guava这种缓存工具来使用。

用到享元模式

String

包装类型(INTEGER、Long等)

Apache Commons Pool21

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-07,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 技术趋势 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 源码下载:https://gitee.com/hong99/design-model/issues/I1IMES
  • 源码下载:https://gitee.com/hong99/design-model/issues/I1IMES总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档