面向对象编程设计模式------享元模式

  所谓享元模式就是运行共享技术有效地支持大量细粒度对象的复用。系统使用少量对象,而且这些都比较相似,状态变化小,可以实现对象的多次复用。
  共享模式是支持大量细粒度对象的复用,所以享元模式要求能够共享的对象必须是细粒度对象。
  在了解享元模式之前我们先要了解两个概念:内部状态、外部状态。
  内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
  外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。
  由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。在我们的程序设计过程中,我们可能会需要大量的细粒度对象来表示对象,如果这些对象除了几个参数不同外其他部分都相同,这个时候我们就可以利用享元模式来大大减少应用程序当中的对象。如何利用享元模式呢?这里我们只需要将他们少部分的不同的部分当做参数移动到类实例的外部去,然后在方法调用的时候将他们传递过来就可以了。这里也就说明了一点:内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。

  享元模式结构:

  享元模式存在如下几个角色:
  Flyweight:抽象享元类。所有具体享元类的超类或者接口,通过这个接口,Flyweight可以接受并作用于外部专题;
  ConcreteFlyweight:具体享元类。指定内部状态,为内部状态增加存储空间。
  UnsharedConcreteFlyweight:非共享具体享元类。指出那些不需要共享的Flyweight子类。
  FlyweightFactory:享元工厂类。用来创建并管理Flyweight对象,它主要用来确保合理地共享Flyweight,当用户请求一个Flyweight时,FlyweightFactory就会提供一个已经创建的Flyweight对象或者新建一个(如果不存在)。
  享元模式的核心在于享元工厂类,享元工厂类的作用在于提供一个用于存储享元对象的享元池,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

public class FlyweightFactory {
    // 享元对象池
    private HashMap<String, FlyWeight> flyWeights = new HashMap<String, FlyWeight>();
    
    public FlyWeight getFlyWeight(String key) {
        // 享元池中存在享元对象,则直接返回
        if(flyWeights.containsKey(key)) {
            return (FlyWeight) flyWeights.get(key);
            
        } else {
            // 享元池中不存在享元对象,并将它放到享元池中
            FlyWeight fw = new ConcreteFlyweight();
            flyWeights.put(key, fw);
            return fw;
        }
    }
}

  实例场景:假如我们有一个绘图的应用程序,通过它我们可以出绘制各种各样的形状、颜色的图形,那么这里形状和颜色就是内部状态了,通过享元模式我们就可以实现该属性的共享了。另外在抽象出一个外部状态即绘图的用户,也就是说绘图的用户对象是不可以共享的,但是当大量用户绘制了相同属性(享元对象内部状态)的对象时,可以返回同一个引用,从而减少系统的对象数量。代码实现如下:

public class User {
    private String name;
    
    public User(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

/**
 * @Description: 抽象形状类,只有一个绘制图型的抽象方法,使用该方法需要传递一个用户对象
 * @author: zxt
 * @time: 2018年7月9日 上午9:43:41
 */
public abstract class Shape {
    public abstract void draw(User user);
}

/**
 * @Description: 绘制图形的具体类
 * @author: zxt
 * @time: 2018年7月9日 上午9:46:16
 */
public class Circle extends Shape {
    // 享元类的内部状态
    private String color;
    
    public Circle(String color) {
        this.color = color;
    }
    
    @Override
    public void draw(User user) {
        System.out.println("用户:" + user.getName() + ",画了一个  '" + color + "' 的圆形!");
    }
}

public class CircleFactory {
    // 享元对象池
    private static HashMap<String, Shape> shapes = new HashMap<String, Shape>();
    
    public static Shape getShape(String key) {
        // 享元池中存在享元对象,则直接返回
        if(shapes.containsKey(key)) {
            return (Shape) shapes.get(key);

        } else {
            // 享元池中不存在享元对象,并将它放到享元池中
            Shape shape = new Circle(key);
            shapes.put(key, shape);
            return shape;
        }
    }
    
    public static int getShapesNum() {
        return shapes.size();
    }
}

public class Client {

    public static void main(String[] args) {
        Shape shape1 = CircleFactory.getShape("红色");
        shape1.draw(new User("张三"));
        
        Shape shape2 = CircleFactory.getShape("灰色");
        shape2.draw(new User("李四"));
        
        Shape shape3 = CircleFactory.getShape("绿色");
        shape3.draw(new User("王五"));
        
        Shape shape4 = CircleFactory.getShape("红色");
        shape4.draw(new User("赵四"));
        
        Shape shape5 = CircleFactory.getShape("灰色");
        shape5.draw(new User("前乾"));
        
        Shape shape6 = CircleFactory.getShape("灰色");
        shape6.draw(new User("孙李"));
        
        System.out.println("一共创建了:" + CircleFactory.getShapesNum() + " 个图形对象!");
    }
}

  模式优缺点
  优点
  1、享元模式的优点在于它能够极大的减少系统中对象的个数。
  2、享元模式由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。
  缺点
  1、由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。
  2、为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

  模式适用场景
  1、如果一个系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。
  2、对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  3、String对象的常量池,以及Integer等包装类的缓存策略:Integer.valueOf(int i)等都使用了享元模式。

  模式总结
  1、享元模式可以极大地减少系统中对象的数量。但是它可能会引起系统的逻辑更加复杂化。
  2、享元模式的核心在于享元工厂,它主要用来确保合理地共享享元对象。
  3、内部状态为不变共享部分,存储于享元对象内部,而外部状态是可变部分,它应当由客户端来负责。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,997评论 6 502
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,603评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,359评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,309评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,346评论 6 390
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,258评论 1 300
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,122评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,970评论 0 275
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,403评论 1 313
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,596评论 3 334
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,769评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,464评论 5 344
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,075评论 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,705评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,848评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,831评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,678评论 2 354

推荐阅读更多精彩内容