设计模式-09-适配器模式-[享元模式]

    技术2023-09-19  101

    1.[享元模式] 是 [对象的适配器模式] 的衍生模式

    2.享元模式简介

    享元模式:是池技术的重要实现方式,使用共享对象可有效地支持大量的细粒度的对象,可以避免大量非常相似的类的开销;

    3.简单案例分析

          案例:公司某部门给员工评优秀员工-很贴合实际哈;

    抽象享元角色: /** * 抽象享元角色 */ public abstract class A1_Flyweight { //内部状态 部门 private String department="公司总部"; //外部状态 员工姓名 【定义成 final 类型的可以先思考下为什么】 private final String employeeName; //要求享元角色必须接受外部状态 public A1_Flyweight(String employeeName){ this.employeeName = employeeName; } //内部状态的 getter/setter public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } //定义业务操作 public abstract void operate(); public String getEmployeeName() { return employeeName; } } 具体的享元角色: /** * 具体的享元角色 */ public class A2_FlyweightRole extends A1_Flyweight { public A2_FlyweightRole(String employeeName){ super(employeeName); } @Override public void operate() { System.out.println(this.getDepartment() +"-"+ this.getEmployeeName() +":优秀员工"); } } 享元工厂: /** * 享元工厂 */ public class A3_FlyweightFactory { //定义一个池容器 private static Map<String,A1_Flyweight> poll = new HashMap<String,A1_Flyweight>(); //享元工厂 public static A1_Flyweight getFlyweight(String employeeName){ A1_Flyweight result = poll.get(employeeName); if(null!=result){ return result; } //根据外部状态创建享元对象 result = new A2_FlyweightRole(employeeName); //放置到池中 poll.put(employeeName,result); return result; } /** * 获取 池容器 中对象数量 */ public static int getSize(){ return poll.size(); } }

    客户端调用:

    /** * 客户端调用 */ public class A4_Client { public static void main(String[] args) { A3_FlyweightFactory factory = new A3_FlyweightFactory(); A2_FlyweightRole role1 = (A2_FlyweightRole)factory.getFlyweight("张三"); A2_FlyweightRole role2 = (A2_FlyweightRole)factory.getFlyweight("张三"); A2_FlyweightRole role3 = (A2_FlyweightRole)factory.getFlyweight("李四"); role1.operate(); role2.operate(); role3.operate(); int size = factory.getSize(); System.out.println("size:"+size); } }

    客户端调用结果:

    公司总部-张三:优秀员工 公司总部-张三:优秀员工 公司总部-李四:优秀员工 size:2

    接收外部状态实现自己的业务逻辑,以便内部业务逻辑对外部状态的依赖。 注意,我们在 抽象享元 中对外部状态加上了 final关键字 ,是为了防止--获得了一个外部状态--然后无意修改了一下--池就混乱了!

    4.享元模式的状态

     享元模式分为:内部状态(intrinsic)与外部状态(extrinsic);

    内部状态

                   内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变,如我们例子中的department,它们          可以作为一个对象的动态附加信息,不必直接储存在具体某个对象中,属于可以共享的部分。

    外部状态

                   外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态,是唯一的一个索引值,如案例中的              employeeName;

    5.享元模式的优缺点

    优点: 享元模式的外部状态相对独立,使得对象可以在不同的环境中被复用(共享对象可以适应不同的外部环境);享元模式可共享相同或相似的细粒度对象,从而减少了内存消耗,同时降低了对象创建与垃圾回收的开销; 缺点: 外部状态由客户端保存,共享对象读取外部状态的开销可能比较大;享元模式要求将内部状态与外部状态分离,这使得程序的逻辑复杂化,同时也增加了状态维护成本;

    6.使用场景

    系统中存在大量的相似对象。细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份。需要缓冲池的场景。

        当然实际工作中享元模式往往会跟其他设计模式协同使用,用的时候按照具体的场景灵活选择即可;

    7.源码分析

         Integer类就是典型的享元模式的例子

    public static Integer valueOf(int i) { if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)]; return new Integer(i); }

    Integer.valueOf中有一个IntegerCache,上面的代码中就对传入的值进行判断。

    如果是从IntegerCache中取出就直接返回,否则就new一个Integer对象。

    这也就是如果传入的int值不在固定的范围类,它们做==的时候一定是false,因为不是同一个对象。其中low=-128,high=127.

     

    还有Long类的valueOf,也是同上的道理。

     

     

    Processed: 0.013, SQL: 12