再战设计模式(十一)之享元模式

享元模式

场景:

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

核心:

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

 

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

类图:如下

 

 类图的看比较复杂.我们来剖析下
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 也是使用的这个模式

posted @ 2019-05-13 22:15  北京de小刀  阅读(158)  评论(0编辑  收藏  举报