精华内容
下载资源
问答
  • 14.3 完整解决方案为了节约存储空间,提高系统性能,Sunny公司开发人员使用享元模式来设计围棋软件中的棋子,其基本结构如图14-4所示:在图14-4中,IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman...

    14.3 完整解决方案

    为了节约存储空间,提高系统性能,Sunny公司开发人员使用享元模式来设计围棋软件中的棋子,其基本结构如图14-4所示:

    这里写图片描述

    在图14-4中,IgoChessman充当抽象享元类,BlackIgoChessman和WhiteIgoChessman充当具体享元类,IgoChessmanFactory充当享元工厂类。完整代码如下所示:

    import java.util.*;  
    
    //围棋棋子类:抽象享元类  
    abstract class IgoChessman {  
        public abstract String getColor();  
    
        public void display() {  
            System.out.println("棋子颜色:" + this.getColor());    
        }  
    }  
    
    //黑色棋子类:具体享元类  
    class BlackIgoChessman extends IgoChessman {  
        public String getColor() {  
            return "黑色";  
        }     
    }  
    
    //白色棋子类:具体享元类  
    class WhiteIgoChessman extends IgoChessman {  
        public String getColor() {  
            return "白色";  
        }  
    }  
    
    //围棋棋子工厂类:享元工厂类,使用单例模式进行设计  
    class IgoChessmanFactory {  
        private static IgoChessmanFactory instance = new IgoChessmanFactory();  
        private static Hashtable ht; //使用Hashtable来存储享元对象,充当享元池  
    
        private IgoChessmanFactory() {  
            ht = new Hashtable();  
            IgoChessman black,white;  
            black = new BlackIgoChessman();  
            ht.put("b",black);  
            white = new WhiteIgoChessman();  
            ht.put("w",white);  
        }  
    
        //返回享元工厂类的唯一实例  
        public static IgoChessmanFactory getInstance() {  
            return instance;  
        }  
    
        //通过key来获取存储在Hashtable中的享元对象  
        public static IgoChessman getIgoChessman(String color) {  
            return (IgoChessman)ht.get(color);    
        }  
    }  

    编写如下客户端测试代码:

    class Client {  
        public static void main(String args[]) {  
            IgoChessman black1,black2,black3,white1,white2;  
            IgoChessmanFactory factory;  
    
            //获取享元工厂对象  
            factory = IgoChessmanFactory.getInstance();  
    
            //通过享元工厂获取三颗黑子  
            black1 = factory.getIgoChessman("b");  
            black2 = factory.getIgoChessman("b");  
            black3 = factory.getIgoChessman("b");  
            System.out.println("判断两颗黑子是否相同:" + (black1==black2));  
    
            //通过享元工厂获取两颗白子  
            white1 = factory.getIgoChessman("w");  
            white2 = factory.getIgoChessman("w");  
            System.out.println("判断两颗白子是否相同:" + (white1==white2));  
    
            //显示棋子  
            black1.display();  
            black2.display();  
            black3.display();  
            white1.display();  
            white2.display();  
        }  
    }  

    编译并运行程序,输出结果如下:

    判断两颗黑子是否相同:true
    判断两颗白子是否相同:true
    棋子颜色:黑色
    棋子颜色:黑色
    棋子颜色:黑色
    棋子颜色:白色
    棋子颜色:白色

    从输出结果可以看出,虽然我们获取了三个黑子对象和两个白子对象,但是它们的内存地址相同,也就是说,它们实际上是同一个对象。在实现享元工厂类时我们使用了单例模式和简单工厂模式,确保了享元工厂对象的唯一性,并提供工厂方法来向客户端返回享元对象。

    【作者:刘伟 http://blog.csdn.net/lovelion

    展开全文
  • 享元模式

    千次阅读 2016-09-20 07:47:07
    享元模式标签 : Java与设计模式 内存属于稀缺资源, 不能随便浪费. 如果有很多相同/相似的对象, 我们可以通过享元节省内存. 内部状态 vs. 外部状态 享元模式(Flyweight): 运用共享技术有效地重用大量细粒度的对象....

    享元模式

    标签 : Java与设计模式


    内存属于稀缺资源, 不能随便浪费. 如果有很多相同/相似的对象, 我们可以通过享元节省内存.


    内部状态 vs. 外部状态

    享元模式(Flyweight): 运用共享技术有效地重用大量细粒度的对象.

    • 享元对象能做到共享的关键是区分了内部状态外部状态:
      此处输入图片的描述
      • 在享元对象内部并且不会随环境改变而改变的共享部分, 可称之为享元对象的内部状态.
      • 随环境改变而改变的、不可以共享的状态是外部状态.

    在设计开发中,有时需要生产大量细粒度对象来表征数据, 如果这些对象除个别参数外基本相同, 此时如果能把那些参数移到类实例外面, 在方法调用时将其传入, 就可以通过共享大幅度减少类实例数目.


    模式实现

    案例: 围棋设计
    

    有下棋经验的同学都知道一盘棋的棋子大小、材质、颜色(黑/白)往往都是确定的, 而围棋落子的位置却不一定(看水平高低了O(∩_∩)O!), 因此我们可以将棋子位置从棋子对象中剥离, 然后让棋子对象共享大小、材质、颜色属性, 并在调用时将位置传入, 就可大大减少棋子对象的数量:
    此处输入图片的描述


    Flyweight

    所有具体享元类的超类或接口, 通过该接口, Flyweight可以接受并作用于外部状态:

    /**
     * @author jifang
     * @since 16/8/26 上午10:27.
     */
    public interface Flyweight {
        void operation(Location location);
    }

    ConcreteFlyweight

    实现Flyweight接口, 并为内部状态增加存储空间:

    class GoFlyweight implements Flyweight {
    
        private String color;
    
        private double radius;
    
        private String material;
    
        public GoFlyweight(String color, double radius, String material) {
            this.color = color;
            this.radius = radius;
            this.material = material;
        }
    
        public String getColor() {
            return color;
        }
    
        public double getRadius() {
            return radius;
        }
    
        public String getMaterial() {
            return material;
        }
    
        @Override
        public void operation(Location location) {
            System.out.println("[" + color + "]棋 [" + material + "]材质 半径[" + radius + "]CM 落在" + location);
        }
    }

    UnsharedConcreteFlyweight

    指不需要共享的Flyweight子类, 因为Flyweight接口共享成为可能, 但它并不强制共享. UnsharedConcreteFlyweight用于解决那些不需要共享对象的问题:

    class Location {
    
        private int locX;
    
        private int locY;
    
        public Location() {
        }
    
        public Location(int locX, int locY) {
            this.locX = locX;
            this.locY = locY;
        }
    
        public int getLocX() {
            return locX;
        }
    
        public void setLocX(int locX) {
            this.locX = locX;
        }
    
        public int getLocY() {
            return locY;
        }
    
        public void setLocY(int locY) {
            this.locY = locY;
        }
    
    
        @Override
        public String toString() {
            return "{" +
                    "locX=" + locX +
                    ", locY=" + locY +
                    '}';
        }
    }
    • FlyweightFactory
      享元工厂,用来创建并管理Flyweight对象,作用是确保合理地共享Flyweight, 当用户请求一个Flyweight时, FlyweightFactory提供一个共享实例:
    public class FlyweightFactory {
    
        private static Map<String, GoFlyweight> map = new ConcurrentHashMap<>();
    
        public static GoFlyweight getGoFlyweight(String color) {
            GoFlyweight flyweight = map.get(color);
            if (flyweight == null) {
                flyweight = new GoFlyweight(color, 1.1, "陶瓷");
                map.put(color, flyweight);
            }
            return flyweight;
        }
    }

    小结

    享元模式可以极大减少内存中对象的数量: 相同/相似对象只保留一份, 节约资源, 提高性能. 且将外部状态剥离, 使外部状态相对独立, 不影响内部状态. 但相比原先的设计, 增加了实现复杂度, 且读取外部状态使得运行时间变长(时间换空间).

    • 场景
      如果一个应用使用了大量对象从而造成很大的存储开销时;
      如果对象的有大量外部状态, 且剥离外部状态就可用相对较少的共享对象取代很多实例时;
      • ‘池’化资源, 如: 线程池、数据库连接池.
      • String类设计.

    参考
    《JAVA与模式》之享元模式
    C#设计模式(12)——享元模式(Flyweight Pattern)

    展开全文
  • 设计模式享元模式

    2021-07-29 13:13:05
    享元模式 1. 介绍 尚硅谷Java设计模式(图解+框架源码剖析) 五分钟设计模式 - 享元模式 菜鸟教程 - 享元模式 1.1 描述和作用 享元漠式(Flyweight Pattern)用共享技术有效地支持大量细粒度的对象 “”表示共享...

    享元模式

    1. 介绍

    尚硅谷Java设计模式(图解+框架源码剖析)

    五分钟设计模式 - 享元模式

    菜鸟教程 - 享元模式

    1.1 描述和作用

    1. 享元漠式(Flyweight Pattern)用共享技术有效地支持大量细粒度的对象
    2. “享”表示共享,“元”表示对象
    3. 常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,在这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
    4. 享元模式能够解决重复对象的内存浪费的问题, 当系统中有大量相似对象,需要缓冲池时。不需要总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率

    1.2 内部状态和外部状态

    1. 内部状态:

      指对象共享出来的信息,存储在向原对象内部,且不会随环境改变

    2. 外部状态:

      指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态


    现实举例:

    下围棋时,棋盘上有很多的棋子,但是只有黑棋和白棋两种颜色。一盘围棋中可能有一白多个黑棋和白棋,这些黑棋或白棋的颜色是可以共享的,而棋子的位置是频繁改变而不可共享的。我们可以使用享元模式,使得棋盘上的棋子只有两个对象:黑棋对象和白棋对象。共享颜色,不共享坐标。


    享元模式提高了系统的复杂性,需要分理处对象的内部状态和外部状态,而外部状态不应该随着内部状态的改变而改变


    2. 原理和角色

    在这里插入图片描述

    1. FlyWeight:是抽象的享元角色,是产品的抽象类。定义了对象的外部状态和内部状态的接口或实现
    2. ConcreteFlyWeight:是具体的享元角色,是具体的产品类。实现了抽象角色定义的相关业务
    3. UnSharedConcreteFlyWeight:是不可共享的角色,一般不会出现在享元工厂中
    4. FlyWeightFactory:享元工厂类,内部提供一个池容器,同时提供从池中存取数据的操作

    3. 应用

    享元模式经典的应用场景就是池技术了,string常量池、数据库连接池、缓冲池等等都是享元模式的应用,享元模式是池技术的重要实现方式

    3.1 Integer源码应用分析

    Integer的valueOf方法:如果参数在-128到127之间,则使用享元模式返回对象

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= Integer.high) {
            // cache是缓存的常量池
            return IntegerCache.cache[i + (-IntegerCache.low)];
        }
        return new Integer(i);
    }
    
    展开全文
  • Java享元模式

    2019-07-17 17:26:36
    享元模式是为了节省内存的模式 内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的 对象,我们可以通过享元模式,节省内存. 享元模式以共享的方式高效地支持大量细粒度对象的重用。 享元对象能...

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

      享元模式以共享的方式高效地支持大量细粒度对象的重用。
      享元对象能做到共享的关键是区分了内部状态和外部状态。
       • 内部状态:可以共享,不会随环境变化而改变
       • 外部状态:不可以共享,会随环境变化而改变

    以围棋的棋子作为示例

    棋子的大小一样,颜色只有两种,在棋盘上的位置是不一样的(很多种可能)

    那么 大小、颜色是棋子的内部状态,

    位置就是棋子的外部状态

    源代码:

    首先我们要限定颜色:

    最好的限定方式就是使用枚举:

    public enum Color {
    
        WHITE(1,"白"),
        BLACK(2,"黑");
    
        private Integer color;
    
        private String colorDesc;
    
        Color(Integer color,String colorDesc){
            this.color = color;
            this.colorDesc = colorDesc;
        }
    
        public Integer getColor() {
            return color;
        }
    
        public void setColor(Integer color) {
            this.color = color;
        }
    
        public String getColorDesc() {
            return colorDesc;
        }
    
        public void setColorDesc(String colorDesc) {
            this.colorDesc = colorDesc;
        }
    }
    

    然后我们就要定义棋子的规范:

    棋子接口: 

    /**
     * 享元模式是为了节省内存的模式
     * 内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的
     * 对象,我们可以通过享元模式,节省内存.
     *
     * 享元模式以共享的方式高效地支持大量细粒度对象的重用。
     * 享元对象能做到共享的关键是区分了内部状态和外部状态。
     *  • 内部状态:可以共享,不会随环境变化而改变
     *  • 外部状态:不可以共享,会随环境变化而改变
     *
     *  下面是享元类要实现的接口
     */
    public interface Chess {
    
        void setColor(Color c);
        Color getColor();
        void display(Coordinate c);
    
    }
    

    棋子实现类:

    public class ChessImpl implements Chess{
    
    
        private Color color;
    
        ChessImpl(Color color){
            this.color = color;
        }
    
        @Override
        public void setColor(Color c) {
            this.color = c;
        }
    
        @Override
        public Color getColor() {
            return this.color;
        }
    
        @Override
        public void display(Coordinate c) {
            System.out.println("棋子颜色:"+this.getColor().getColorDesc());
            System.out.println("棋子位置:x:" + c.getX() + " y:" + c.getY());
        }
    }
    

    我们要获取棋子,就只能使用工厂模式,保证内存资源合理利用:

    /**
     * 享元工厂
     */
    public class ChessFactory {
    
        private static Map<Color,Chess> chessMap = new HashMap<>();
    
        public static int size(){
            return chessMap.size();
        }
    
        /**
         * 如果有同意颜色的棋子就返回,如果没有就创建后put再返回
         * @param color 棋子 颜色
         * @return 棋子
         */
        public static Chess getChess(Color color){
            if (chessMap.get(color) != null){
                return chessMap.get(color);
            } else {
                Chess chess = new ChessImpl(color);
                chessMap.put(color,chess);
                return chess;
            }
    
        }
    }

    测试代码:

    public class FlyWeightTest {
    
        public static void main(String[] args) {
            System.out.println("没有获取棋子时,棋子工厂大小" + ChessFactory.size());
            System.out.println();
    
            Chess whiteChess1 = ChessFactory.getChess(Color.WHITE);
            System.out.println("1.获取第一颗白棋子时,棋子工厂大小" + ChessFactory.size());
            whiteChess1.display(new Coordinate(2,3));
            System.out.println();
    
            Chess whiteChess2 = ChessFactory.getChess(Color.WHITE);
            System.out.println("2.获取第二颗白棋子时,棋子工厂大小" + ChessFactory.size());
            whiteChess2.display(new Coordinate(2,3));
            System.out.println();
    
            System.out.println("第一颗白棋子和第二颗白棋子是否是一个对象" + (whiteChess1.hashCode() == whiteChess2.hashCode()));
            System.out.println();
    
            Chess blackChess1 = ChessFactory.getChess(Color.BLACK);
            System.out.println("3.获取第一颗黑棋子时,棋子工厂大小" + ChessFactory.size());
            blackChess1.display(new Coordinate(4,3));
            System.out.println();
    
            Chess blackChess2 = ChessFactory.getChess(Color.BLACK);
            System.out.println("4.获取第二颗黑棋子时,棋子工厂大小" + ChessFactory.size());
            blackChess2.display(new Coordinate(5,3));
            System.out.println();
    
            System.out.println("第一颗黑棋子和第二颗黑棋子是否是一个对象" + (blackChess1.hashCode() == blackChess2.hashCode()));
            System.out.println();
    
        }
    }

    测试结果:

    没有获取棋子时,棋子工厂大小0
    
    1.获取第一颗白棋子时,棋子工厂大小1
    棋子颜色:白
    棋子位置:x:2 y:3
    
    2.获取第二颗白棋子时,棋子工厂大小1
    棋子颜色:白
    棋子位置:x:2 y:3
    
    第一颗白棋子和第二颗白棋子是否是一个对象true
    
    3.获取第一颗黑棋子时,棋子工厂大小2
    棋子颜色:黑
    棋子位置:x:4 y:3
    
    4.获取第二颗黑棋子时,棋子工厂大小2
    棋子颜色:黑
    棋子位置:x:5 y:3
    
    第一颗黑棋子和第二颗黑棋子是否是一个对象true

    结果可以表明,工厂里就维护了两个棋子对象,一个黑一个白,只要获取每种颜色的棋子一次后,之后获取任何颜色的棋子都是第一次获取颜色的那个对象

    这样就能节省内存:

    那么享元模式的优点和缺点呢:

    优点:

    1. 节约系统的开销。保证一个常用的对象只有一个!
    2. 外部状态不会影响内部状态,可以在不同环境下进行共享哦。

    缺点:

    1. 享元模式使逻辑变得更加复杂,需要将享元对象分出内部状态和外部状态。
    2. 并且为了使对象可以共享,外部状态在很多情况下是必须有的,比如围棋的位置。当读取外部状态时明显会增加运行时间。

    使用场景:

    一个系统有大量细粒度化的对象,占据大量的内存。
    对象大部分属性可以外部化,并且能将外部的属性放入内部属性中来。
    使用享元模式需要维护享元池,所以要用那种常用的经常调用的对象可以使用享元模式。

    展开全文
  • Java享元模式(FlyWeight)

    千次阅读 2019-03-15 23:52:45
    享元模式   内存属于稀缺资源,不要随便浪费。如果有很多个完全相同或相似的 对象,我们可以通过享元模式,节省内存. 核心: 享元模式以共享的方式高效地支持大量细粒度对象的重用。 享元对象能做到共享的关键是...
  • 设计模式--享元模式

    2019-11-25 13:56:14
    设计模式享元模式 享元模式应用场景 享元模式的英文名又叫Flyweight,意思是轻量级,而我们翻译的中文名享元个人感觉比轻量级的直译更好。 享元模式的定义是:使用共享技术有效地支持大量细粒度的对象。 通俗的来...
  • 设计模式-享元模式

    2020-07-23 11:12:41
    设计模式-享元模式 1、基本介绍 享元模式(Flyweight Pattern)也叫蝇绳模式:运用共享技术有效地支持大量细粒度的对象。 常用于系统底层开发,解决系统的性能问题。像 数据库连接池 ,里面都是创建好的连接对象,在...
  • Java设计模式-享元模式

    千次阅读 2019-03-26 14:54:09
    享元模式
  • 五、享元模式的原理类图 六、内部状态和外部状态 七、享元模式解决网站展现项目 八、享元模式在 JDK-Interger的应用源码分析 九、享元模式的注意事项和细节 一、展示网站项目需求 小型的外包项目,给客户 A做...
  • 设计模式 | 享元模式

    2021-04-08 23:25:56
    1 | 享元模式的概述 如果一个软件系统在运行时所创建的相同或相似的对象数量太多,将导致运行代价过高,带来系统资源浪费、性能下降等问题。 例如:在一个文本字符串中存在很多重复的字符,如果每一个字符都用一个...
  • 设计模式:结构型-享元模式

    多人点赞 2021-04-09 16:11:46
    目录第一章 享元模式介绍第二章 享元模式实现2.1、非享元对象2.2、抽象享元对象2.3、具体享元对象2.4、原工厂对象2.5、最终测试类第三章 享元模式应用 项目地址:https://gitee.com/caochenlei/design-pattern ...
  • 1.享元模式的定义与特点 享元(Flyweight)模式的定义:运用共享技术来有効地支持大量细粒度对象的复用。它通过共享已经存在的又橡来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率...
  • 设计模式-享元模式(外包真香)

    千次阅读 多人点赞 2021-03-19 09:53:48
    享元模式(Flyweight Pattern) 也叫蝇量模式,是一种结构型模式,“”就表示共享,“”表示对象。运用共享技术有效地支持大量细粒度的对象,享元模式能够解决重复对象的内存浪费的问题,当系统中有大量相似对象...
  • 本咸鱼开始修炼内功了,加油,奥利给!!! 问题引出 如果我们做一个小型外包网站项目,有的客户想以新闻的形式发布,有的客户...享元模式(Flyweight Pattern)也称蝇量模式 享元模式能够解决重复对象的内存浪费...
  • 文章目录1、示例案例-围棋棋子的设计2、享元模式概述2.1、享元模式定义2.2、享元模式结构2.3、享元模式结构图中角色2.4、享元模式典型实现3、围棋棋子-享元模式完整解决方案4、带外部状态的解决方案5、单纯享元模式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 893
精华内容 357
关键字:

享元模式围棋