设计模式之享元模式

什么是享元模式

“享元”,这是什么,这词不是很常见啊,不像工厂模式、建造者模式等,看见名字就能大概猜个八九不离十。

  • 享,即共享。
  • 元,是指一个单位,或者说是一个对象。

享元模式是运用共享技术有效地支持大量细粒度的对象的设计模式。

由于是细粒度单位的共享,享元模式又叫蝇量模式。

原理图

在这里插入图片描述

注意:内部状态与外部状态

使用享元模式,一定要分清什么可以共享(内部状态),什么不能共享(外部状态)。

  • 内部状态是指对象共享出来的信息,储存在享元对象内部且不会随着环境的改变而改变。
  • 外部状态是指对象得以依赖的一个标记,是随着环境的改变而改变的、不可共享的状态。

比如一盘围棋比赛,有黑白两种棋子,有361个落点。如果不适用享元模式,每一个落点都需要new一个棋子,即使服务器可以撑得住一场对局的进行,那么同时上万场呢?

对于一个颜色棋子来说,他们的外形、颜色是一样的,只是落点不同。那么将落点这个属性分离出去,仅仅需要两个棋子实例就足以应对所有的对局。

在这里,外形、颜色等细粒度的参数,是棋子的内部状态,而落点这样细粒度的参数是棋子的外部状态

为什么要用享元模式

老李收编了一支乐队

李云龙打仗回来,发现了草丛里有一支乐队,便让乐队吹了一曲,感觉不错。收编了吧,不过这曲子,得换成咱八路的曲子。

战争时期,乐队也不是频繁出现的队伍,只在重大仪式时才会演奏,原来给原部队奏乐,现在给共八路奏乐,也不会出现同时奏乐的冲突(毕竟被收编了嘛)。

用代码的逻辑描述一下收编,怎么收编?怎么换成八路的曲子?

  1. 按照原有乐队,复制粘贴一份,改改奏乐的类型。
    • 但是这不就有俩乐队了,不合适
  2. 找到这个乐队的类,再new一个。
    • 现在俩乐队,曲一样,不合适。
  3. 用享元模式,乐队还是这么个乐队,教他们吹八路的曲子。
    • 既然是享元模式,共享什么?共享这个乐队(这是内在状态,乐队有几个人、都是谁、用的什么乐器……)
    • 外部状态是什么?外部状态是曲子现在是八路的曲子,别人来做客,也能吹吹别人的曲子。

代码模拟

首先要有一个抽象乐队类:

public abstract class AbstractBand {
    public abstract void play(Tune tune);
}

有一个曲子类:

public class Tune {
    private String name;

    public Tune(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

有一支乐队:

public class Band extends AbstractBand {
    private String name;

    public Band(String name) {
        this.name = name;
    }

    @Override
    public void play(Tune tune) {
        System.out.println(name + "演奏" + tune.getName());
    }
}

用于管理乐队的“乐队工厂”:

import java.util.HashMap;
import java.util.Map;

public class BandFactory {
    private Map<String, Band> bands = new HashMap();

    public AbstractBand getBand(String name) {
        if (!bands.containsKey(name)) {
            bands.put(name, new Band(name));
        }
        return bands.get(name);
    }

    public int getTunesNumber(){
        return bands.size();
    }
}

李云龙:

public class LiYunLong {
    public static void main(String[] args) {
        BandFactory factory = new BandFactory();
        AbstractBand band1 = factory.getBand("八路的乐队");
        AbstractBand band2 = factory.getBand("八路的乐队");
        Tune tune1 = new Tune("八路的曲子");
        Tune tune2 = new Tune("国军的曲子");

        band1.play(tune1);
        band2.play(tune2);
        System.out.println("现在的乐队数:" + factory.getTunesNumber());
    }
}

输出结果:

八路的乐队演奏八路的曲子
八路的乐队演奏国军的曲子
现在的乐队数:1
当前类图

在这里插入图片描述

享元模式和单例模式很像?

需要回顾单例模式可以点击链接进行跳转
同样都是减少new的次数,同样都是一个对象给不同的调用方调用,他俩似乎还真有点相似。

需要注意的一点是,单例模式是创建型设计模式,享元模式是结构型设计模式

关于二者不同点:

  • 单例模式是整个应用系统共用一个实例对象;享元模式是整个系统共用好几个同类型对象。
  • 单例模式绝对不会重复创建第二个对象,享元模式是按需分配,不够会进行创建。

关于享元模式怎么共享:

享元模式的共享对象在使用时是线程私有的,是有借有还的,在宏观上是共享的。

关于连接池:

连接池本身是单例模式,但是连接池里的多个连接对象是享元模式。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值