• 7享元模式


    享元模式

    享元模式(Flyweight Pattern) 是池技术的重要方式,可以降低大量的重复的、细粒度的类在内存中的开销。

    1享元模式的定义

    享元模式的英文原文是:
    Use sharing to support large numbers of fine-grained objects efficiently.

    意思是:使用共享对象可有效的支持大量细粒度的对象。

    享元模式是以共享模式高效的支持大量的细粒度对象。享元对象能做到共享的关键是区分内部状态(Internal State) 和外部状态(External State)。
    • 内部状态是存储在享元对象内部的、可以共享的信息,并且不会随环境改变而改变。
    • 外部状态是随环境改变而改变且不可以共享的状态。享元对象的外部状态必须有客户端保存,并且在享元对象被创建之后,在需要使用的时候再传入到享元对象的内部。

    享元模式有4个角色:
    • 抽象享元(Flyweight )角色:该角色对享元类进行抽象,需要外部状态的操作可以通过参数的形式将外部状态传入。
    • 具体享元(Concrete Flyweight)角色:该角色实现抽象享元定义的业务,注意享元对象可以在系统内共享。
    • 享元工厂(FlyweightFactory)角色:构造一个池容器,并负责创建和管理享元角色,提供从池容器中获得对象的方法,保证享元对象可以被系统适当的共享。当一个客户端对象请求一个享元对象时,享元工厂角色会去检查系统中是否已经有一个符合要求的享元对象。如果已经有了,享元工厂则提供这个已有的享元对象;否则创建一个合适的享元对象。
    • 客户端(Client)角色:该角色需要自行存储所有享元对象的外部状态。

    注意:除了上面的4个角色,享元模式还会涉及符合享元角色,该角色是将一些单纯享元使用合成模式加以复合,形成复合享元对象,这些复合享元对象本身不能共享,不会出现在享元工厂中,因此也称为“不可共享的享元角色”。但可以降负荷享元对象分解成单纯的享元对象,而后者则可以共享。

    享元的类图
    创建抽象享元角色
    Flyweight.java
    package com.eric.结构型模式.享元模式.引例;
    
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 抽象享元角色
     * @CreateTime 2020-12-03 11:27:05
     */
    public interface Flyweight {
        //业务方法
        public abstract void operation(String  extrinsicState);
    }
    抽象享元角色声明一个业务方法operation(),该方法的参数书享元对象的外部状态。
    具体享元ConcreteFlyweight实现抽象享元Flyweight接口。

    创建具体享元
    Concrete.java
    package com.eric.结构型模式.享元模式.引例;
    
    
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 具体享元
     * @CreateTime 2020-12-03 11:29:24
     */
    public class ConcreteFlyweight implements Flyweight{
        private String intrinsicState; //内部状态
        ConcreteFlyweight(String intrinsicState){
            this.intrinsicState = intrinsicState;
        }
    
        @Override
        public void operation(String extrinsicState) {
            System.out.println("内部状态"+intrinsicState+"---外部状态"+extrinsicState);
        }
    }
    具体享元类定义了一个IntrnsicState属性,该属性用于村相互享元对象的内部状态,并通过构造函数中的参数对内部状态进行赋值。

    享元工厂
    FlyweightFactory.java
    package com.eric.结构型模式.享元模式.引例;
    
    import java.util.HashMap;
    import java.util.Map;
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 享元工厂
     * @CreateTime 2020-12-03 11:33:03
     */
    public class FlyweightFactory {
        private static Map<String,Flyweight> pool = new HashMap<String, Flyweight>();
        private FlyweightFactory(){}//私有构造方法
        public static Flyweight getFlyweight(String intrinsicState){
            Flyweight flyweight = pool.get(intrinsicState);
            if(flyweight == null){
                flyweight = new ConcreteFlyweight(intrinsicState);
                pool.put(intrinsicState,flyweight);
            }
            return flyweight;
        }
    }
    享元工厂使用一个静态的Map集合来存放享元对象,该集合是池容器。静态方法getFlyWeight()可以根据内部的状态值获取享元对象。因为内部状态不改变,所以可以作为主键,并根据气质从池容器中获取享元对象即可;如何池容器中无对应的享元对象,则创建一个新的享元对象并保存到池容器中。

    2享元模式的应用

    a.享元模式的优缺点
    享元模式的优点在于答复减少内存中对象的数量,降低程序内存的占用,提高性能。但是,相应付出的代价也很高。
    • 享元模式增加了系统的复杂性,需要分出外部状态和内部状态,而且内部状态具有固化特性,不应该随外部状态改变而改变,这使得程序的逻辑复杂化。
    • 享元模式将享元对象的状态外部化,而读取外部状态使得运行时间变长。
    b.享元模式的使用场景
    使用享元模式的典型场景。
    • 系统中有大量的相似对象,这些对象耗费大量内存。
    • 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关,几对象没有特定的身份。
    Java基础类库中大量使用了享元模式,如String、Integer、Boolean、Character等类都通过享元模式提供了内部的池化机制。

    3享元模式的实例

    利用享元模式模拟下棋的过程。
    定义棋子接口,规范落子方法put(),对棋子进行定位。
    Chesspiece.java
    package com.eric.结构型模式.享元模式.例1;
    
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 棋子接口规范
     * @CreateTime 2020-12-03 13:17:38
     */
    public interface Chesspiece  {
        //落子
        void put(int x,int y);
    }
    ChesspieceFlyweight.java
    package com.eric.结构型模式.享元模式.例1;
    
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 棋子具体享元
     * @CreateTime 2020-12-03 13:48:48
     */
    public class ChesspieceFlyweight implements Chesspiece {
        private String color;
    
        public ChesspieceFlyweight(String color){
            this.color = color;
        }
    
        @Override
        public void put(int x, int y) {
            System.out.println("在("+x+","+y+")位置放了一个"+color+"子");
        }
    }
    color属性是棋子的内部状态,构造函数带参数对color赋值,并实现落子put()方法;
    棋子工厂
    棋子工厂是享元工厂,负责创建和管理棋子。
    ChesspieceFactory.java
    package com.eric.结构型模式.享元模式.例1;
    
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 棋子工厂
     * @CreateTime 2020-12-03 13:55:23
     */
    public class ChesspieceFactory {
       private static final Chesspiece WHITE = new ChesspieceFlyweight("白");
       private static final Chesspiece BLACK = new ChesspieceFlyweight("黑");
    
        public static Chesspiece getChesspiece(String color){
            if("白".equals(color))return WHITE;
            else if("黑".equals(color))return BLACK;
            return null;
        }
    }
    下棋时只需要黑白两种棋子,所以在棋子工厂ChesspieceFactory中直接创建黑白棋子对象,因此没有用Map集合来存放棋子对象。getChesspiece()方法根据颜色返回相应的棋子对象。
    测试类
    Game.java
    package com.eric.结构型模式.享元模式.例1;
    
    /**
     * @author Eric
     * @ProjectName my_design_23
     * @description 开始游戏
     * @CreateTime 2020-12-03 14:00:09
     */
    public class Game {
        public static void main(String[] args) {
            Chesspiece chesspiece1 = ChesspieceFactory.getChesspiece("黑");
            chesspiece1.put(3,3);
            Chesspiece chesspiece2 = ChesspieceFactory.getChesspiece("白");
            chesspiece2.put(3,4);
            Chesspiece chesspiece3= ChesspieceFactory.getChesspiece("黑");
            chesspiece3.put(2,4);
            Chesspiece chesspiece4 = ChesspieceFactory.getChesspiece("白");
            chesspiece4.put(4,4);
        }
    }
    测试结果






    只要你不停下来,慢一点也没关系。
  • 相关阅读:
    Unity3D脚本修改默认编码界面
    Winform异步初始化UserControl的问题
    Windows API实现移动窗体
    BackgroundWorder控件
    Winform复杂界面异步加载
    TabControl设置选项卡的大小
    VS2010尝试运行项目时出错,无法启动程序
    winform开发-CheckedListBox控件
    tomcat配置https访问
    用户svn密码自定义
  • 原文地址:https://www.cnblogs.com/zyl-0110/p/14204692.html
Copyright © 2020-2023  润新知