zoukankan      html  css  js  c++  java
  • 再战设计模式(十一)之享元模式

    享元模式

    场景:

    内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的 对象,我们可以通过享元模式,节省内存.

    核心:

    本质:享元模式以共享的方式高效地支持大量细粒度对象的重用
    享元对象能做到共享的关键是区分了内部状态和外部状态
    内部状态:可以共享,不会随环境变化而改变
    外部状态:不可以共享,会随环境变化而改变
     
    现在有个需求,需要为围棋设置一个程序,那么围棋的棋子改如何设计?总共有很多黑子和白子,难道我们需要为每一个棋子生成一个对象吗?

    显然这样的设计是不合理的.这个时候我们就可以用到享元模式!

    类图:如下

     类图的看比较复杂.我们来剖析下
    chessFlyWeight:是一个接口,声明了一些公共的方法,这些方法可以向外提供内部状态,以及设置外部的状态
    ChessFlyWeightImpl: 是一个享元对象的实例,可以存储内部状态(因为可以共享) ,可以获取外部状态的属性.如 x y 
    ChessCoordinateConcrete: 是享元对象的外部状态不可以共享,,可以随意设置
    ChessFlyWeightFactory : 就是通过内部状态.获取对象..就像我们平时用的缓存一样.我把他设置成单例的了.
    client: 可以具体的调用这里就不多说了.
     

    代码:

    /**
     * 享元类
     * @Created by xiaodao
     */
    public interface ChessFlyWeight {
    
        void setColor(String color );
        String getColor();
        void display(ChessCoordinateConcrete c );
    
    }
    
    /**
     * 为内部对象,提供享元存储.!!
     * @Created by xiaodao
     */
    public class ChessFlyWeightImpl implements ChessFlyWeight {
        private String color;
    
        public ChessFlyWeightImpl(String color) {
            this.color = color;
        }
    
        public void setColor(String color) {
            this.color = color;
        }
    
        public String getColor() {
            return this.color;
        }
    
        public void display(ChessCoordinateConcrete c) {
    
            System.out.println("chess's color = "+ color);
            System.out.println("chess;s position x = "+ c.getX() +"----- y = "+ c.getY());
    
    
        }
    }
    
    
    /**
     * 不可共享的外部结构
     * @Created by xiaodao
     */
    public class ChessCoordinateConcrete {
    
        private int x,y;
    
        public ChessCoordinateConcrete(int x, int y) {
            this.x = x;
            this.y = y;
        }
    
    
        public int getX() {
            return x;
        }
    
        public void setX(int x) {
            this.x = x;
        }
    
        public int getY() {
            return y;
        }
    
        public void setY(int y) {
            this.y = y;
        }
    }
    
    
    
    /**
     * 享元 工厂 返回 接口...
     * @Created by xiaodao
     */
    public class ChessFlyWeightFactory {
    
        private static  ChessFlyWeightFactory instance= new ChessFlyWeightFactory();
    
    
        private static HashMap<String,ChessFlyWeight> map = new HashMap<String, ChessFlyWeight>();
    
        public  ChessFlyWeight getChess(String color){
            if(map.get(color) !=null){
                return map.get(color);
            }else{
                ChessFlyWeight chessFlyWeight = new ChessFlyWeightImpl(color);
                map.put(color,chessFlyWeight);
                return  map.get(color);
            }
    
        }
    
        private ChessFlyWeightFactory() {
        }
    
        public static ChessFlyWeightFactory getInstance(){
            return instance;
        }
    }
    /**
     * @Created by xiaodao
     */
    public class Client {
    
        public static void main(String[] args) {
            ChessFlyWeightFactory c =  ChessFlyWeightFactory.getInstance();
    
            ChessFlyWeight chess1 = c.getChess("黑色");
    
            chess1.display(new ChessCoordinateConcrete(10,20));
    
            ChessFlyWeight chess2 = c.getChess("黑色");
            System.out.println("-----------------");
            chess2.display(new ChessCoordinateConcrete(20,30));
    
            System.out.println(chess1);
            System.out.println(chess2);
    
    
        }
    
    }
    
    获取到的结果:
    
    chess's color = 黑色
    chess;s position x = 10----- y = 20
    -----------------
    chess's color = 黑色
    chess;s position x = 20----- y = 30
    disign.flyweight.ChessFlyWeightImpl@6e0be858
    disign.flyweight.ChessFlyWeightImpl@6e0be858

    这样的运行之后..我们就可以获取到同一个对象,但是他的外部不可共享的属性确不一样..这就可以节省很多内存空间.

    角色:

    享元模式实现: 

    – FlyweightFactory享元工厂类
    • 创建并管理享元对象,享元池一般设计成键值对

    – FlyWeight抽象享元类

    • 通常是一个接口或抽象类,声明公共方法,这些方法可以向外界提供对象 的内部状态,设置外部状态。

    – ConcreteFlyWeight具体享元类
    • 为内部状态提供成员变量进行存储

    – UnsharedConcreteFlyWeight非共享享元类

    • 不能被共享的子类可以设计为非共享享元类 

    总结:

    享元模式,我们在工作中很少用,写起来比较复杂.维护也不好维护,但是我们还是需要了解,这样对阅读源码是比较友好的.

    优点:

    1. 极大的减少了内存中的对象数量
    2. 相同或者相似的对象内存中只有一份,节省空间
    3. 外部状态相对独立,不影响内部的属性

    缺点:

    1. 模式比较复杂.看上面的类图就知道,感觉不够清晰,是程序逻辑复杂化
    2. 为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。 用时间换取了空间

     JDK或者项目中的使用

    string 也是使用的享元模式,共享常量池.

    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 a = Integer.valueOf(100);
            Integer b = 100;
    
            Integer c =Integer.valueOf(1000);
            Integer d = Integer.valueOf(1000);
            System.out.println(a==b);
            System.out.println(c==d);

    true
    false

    integer 最小是-128 最大是127 在缓存中,当然也可以设置.也是使用的享元模式

    数据连接池还有各种pool 也是使用的这个模式

  • 相关阅读:
    react创建项目01
    jq中的时间转化
    vue-resource调用promise取数据方式整理
    ES6 语法
    js获取时间
    trigger()模拟事件操作
    移动端调出不同需求的键盘
    移动端ios滚动卡顿问题
    godaddy购买的域名解析到aws的route53
    k8s 排错
  • 原文地址:https://www.cnblogs.com/bj-xiaodao/p/10859371.html
Copyright © 2011-2022 走看看