美文网首页
享元模式

享元模式

作者: 贾里 | 来源:发表于2017-08-07 15:29 被阅读35次

    1.定义

    用来尽可能减少内存使用量,适用于可能存在大量重复对象的场景,来缓存可共享的对象。避免创建过多的对象。
    使用共享对象可有效地支持大量的细粒度的对象。

    应用场景:如果项目中有很多完全相同或相似的对象,则可以使用享元模式,节省内存。

    核心
    享元对象能做到共享的关键就是区分了内部状态和外部状态。

    • 内部状态:可以共享,不会随环境变化而变化
    • 外部状态:不可以共享,会随环境变化而变化
    享元模式.png

    例子:
    火车购票系统,很多客户端不断访问服务器,服务器去查询数据库,然后返回给客户端;如果每次查询结果都用创建的形式,
    那么必将创建大量的对象;比如A-B城市,就那么几趟车,座位也就几种;如果将这些数据缓存起来,就不用每次都创建了。
    当数据库查询之后,先从缓存中取,如果没有在创建对象。

    2.角色

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

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

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

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

    3.代码实现

    例如:围棋中的享元模式,在围棋中,所有的白色或黑色的(形状、大小,颜色都一样)只是位置不同,那像这样的情况,可以使用享元模式。
    把颜色、形状、大小给共享出来(内部状态)。位置不共享(外部状态)

    享元模式例子.png

    FlyWeight(抽象享元类)

    /**
     * 享元类接口:可以共享的有颜色,大小,形状
     * FlyWeight(抽象享元类):通常是一个接口或者抽象类,声明公共方法,
     * 这些方法可以向外界提供对象的内部状态,设置外部状态。
     */
    public interface ChessFlyWeight {
        //这里只设置一个颜色,大小和形状省略
        void setColor(String c);
        String getColor();
        void display(Coordinate c);//显示棋子
    }
    

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

    //享元的具体实现:ConcreteFlyWeight(具体享元类):为内部状态提供成员变量进行存储
    class concreteFlyWeight implements ChessFlyWeight{
        private String color;//这里就是为内部状态提供成员变量进行存储
        //构造的时候初始化color属性
        public concreteFlyWeight(String color) {
            super();
            this.color = color;
        }
        @Override
        public void setColor(String c) {
            this.color = c;
        }
        @Override
        public String getColor() {
            return color;
        }
        @Override
        public void display(Coordinate c) {
            System.out.println("棋子颜色:"+color);
            System.out.println("棋子位置:("+c.getX()+","+c.getY()+")");
        }
    }
    

    UnsharedConcreteFlyWeight(非共享享元类):不能被共享的子类可以设计为非共享享元类

    /**
     * 坐标类(外部状态):棋子位置
     * UnsharedConcreteFlyWeight(非共享享元类):不能被共享的子类可以设计为非共享享元类
     */
    public class Coordinate {
        private int x,y;//坐标位置
        public Coordinate(int x, int y) {
            super();
            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;
        }
    }
    

    FlyweightFactory(享元工厂类)

    /**
     * 享元工厂
     * FlyweightFactory(享元工厂类):创建并管理享元对象,享元池一般设计成键值对
     */
    public class ChessFlyWeightFactory {
        //享元池:存放享元对象
        private static Map<String,ChessFlyWeight> map = new HashMap<String,ChessFlyWeight>();
        //提供一个享元工厂:创建和管理棋子
        public static ChessFlyWeight getChess(String color){
            if (map.get(color) != null ) {
                return map.get(color);
            }else{
                ChessFlyWeight chess = new concreteFlyWeight(color);
                map.put(color, chess);
                return chess;
            }
        }  
    }
    

    客户端

    public static void main(String[] args) {
        ChessFlyWeight chess1 = ChessFlyWeightFactory.getChess("黑色");//黑1
        ChessFlyWeight chess2 = ChessFlyWeightFactory.getChess("黑色");//黑2
        System.out.println(chess1==chess2);//结果为true,相同或相似对象内存中只存在一份
          
        //使用享元的外部状态
        chess1.display(new Coordinate(10, 10));//黑1在10,10的位置
        chess2.display(new Coordinate(20, 20));//黑2在20,20的位置
          
    }
    

    输出结果

    true
    
    棋子颜色:黑色
    
    棋子位置:(10,10)
    
    棋子颜色:黑色
    
    棋子位置:(20,20)
    

    4.总结

    应用场景

    比如线程池,数据库连接池,这些都利用享元模式共享了部分属性,在池中操作。

    String类的设计也是享元模式

    优点:

    • 1.极大的减少内存中对象的数量

    • 2.相同或相似对象内存中只存在一份,极大的节约资源,提高系统性能

    • 3.外部状态相对独立,不影响内部状态

    缺点:

    • 1.模式较复杂,使程序逻辑复杂化

    • 2.为了节省内存,共享了内部状态,分离出外部状态,而读取外部状态使运行时间变长。

    5.Android中

    android handler的消息队列中消息的不断创建、更新、销毁,可以利用享元模式;

    相关文章

      网友评论

          本文标题:享元模式

          本文链接:https://www.haomeiwen.com/subject/upfmlxtx.html