享元模式

作者: Jackson杰 | 来源:发表于2019-04-10 13:53 被阅读14次

一 定义

享元模式是池技术的重要实现。

定义:使用共享对象可有效地支持大量的细粒度的对象。

享元模式的定义为我们提出了两个要求,细粒度的对象和共享对象。我们知道创建过多的对象分配到内存中很容易造成内存溢出,享元模式就可以尽可能地减少内存的使用量,比较适用于可能存在大量重复对象的场景,通过共享技术,避免创建过多的对象。

先来了解两个概念:内部状态和外部状态

  • 内部状态
    内部状态是对象可以共享出来的信息,存储在享元对象内部并且不会随着环境改变而改变。

  • 外部状态
    外部状态是对象得以依赖的一个标记,是随着环境改变而改变的,不可以共享的状态。

二 模式结构

角色介绍:

  • Flyweight:抽象享元角色
    享元对象的抽象基类或者接口。

  • ConcreteFlyweight:具体享元角色
    具体的一个产品类,实现抽象角色定义的业务。

  • FlyweightFactory:享元工厂
    负责管理享元对象池和创建享元对象。

三 实例

  • 抽象享元角色,一般为抽象类。在抽象角色中,一般需要把外部状态和内部状态定义出来,当然,如果没有内部状态,也是可以的。
    内部状态是共享出来的,不随环境改变而改变。
    外部状态是对象作为依赖的标记。
public abstract class Flyweight {
    // 内部状态
    private String intrinsic;

    // 外部状态
    protected final String Extrinsic;

    // 要去享元角色必须接收外部状态
    public Flyweight(String extrinsic){
        this.Extrinsic=extrinsic;
    }

    // 定义业务操作
    public abstract void operate();

    // 内部状态的getter/setter

    public String getIntrinsic() {
        return intrinsic;
    }

    public void setIntrinsic(String intrinsic) {
        this.intrinsic = intrinsic;
    }
}
  • 具体的享元角色
    实现自己的业务逻辑,然后接收外部状态,以便内部业务逻辑对外部状态的依赖。
public class ConcreteFlyweight extends Flyweight{
    // 接受外部状态
    public ConcreteFlyweight(String extrinsic) {
        super(extrinsic);
    }

    // 根据外部状态进行逻辑处理
    @Override
    public void operate() {
        // 业务处理

    }
}
  • 不需要共享的Flyweight子类
public class UnsharedConcreteFlyweight extends Flyweight{

    public UnsharedConcreteFlyweight(String extrinsic) {
        super(extrinsic);
    }

    @Override
    public void operate() {

    }
}
  • 享元工厂
public class FlyweightFactory {
    // 定义一个池容器
    private static HashMap<String, Flyweight> pool = new HashMap<>();

    // 享元工厂
    public static Flyweight getFlyweight(String Extrinsic) {

        // 需要返回的对象
        Flyweight flyweight=null;

        // 在池中没有该对象
        if (pool.containsKey(Extrinsic)){
            flyweight=pool.get(Extrinsic);
            System.out.print("已有 " + Extrinsic + " 直接从池中取---->\n");
        }else {
            // 根据外部状态创建享元对象
            flyweight=new ConcreteFlyweight(Extrinsic);
            // 放置到池中
            pool.put(Extrinsic,flyweight);
            System.out.print("创建 " + Extrinsic + " 并从池中取出---->\n");
        }

        return flyweight;

    }
}
  • 测试代码
 Flyweight flyweightX = FlyweightFactory.getFlyweight("X");
 Flyweight flyweightY = FlyweightFactory.getFlyweight("Y");
  Flyweight flyweightZ = FlyweightFactory.getFlyweight("Z");
  Flyweight flyweightReX = FlyweightFactory.getFlyweight("X");
   Flyweight unsharedFlyweight = new UnsharedConcreteFlyweight("X");
  • 运行结果


我们以过年回家买火车票为例,过年回家买火车票是件痛苦的事情,很多人都用书票软件向服务端发出请求,对于每个请求,服务端必须做出应答。在用户设置了出发地和目的地后,每次请求都要返回查询结果,当无数的人请求时,如果每次都需要重新创建一个查询结果,那么必然造成大量重复对象的创建,销毁等,使得内存占用率高居不下,所以这个问题可以通过享元模式得到很好的解决。
对于一列火车来说,我们拿高铁举例,
不变的状态比如高铁的名字都是复兴号。
变化的状态是出发城市和终止城市。

  • 创建抽象享元对象
    我们把火车的始发城市和终止城市作为外部状态,然后定义业务逻辑,根据座位等级,显示车票票价。
public abstract class Ticket {

    // 内部状态
    private String name="和谐号";

    // 外部状态
    protected String from;
    protected String to;

    public Ticket(String from,String to){
        this.from=from;
        this.to=to;
    }

    // 定义业务逻辑,根据座位等级,显示价格
    public abstract void showTicketInfo(String seat);


    public String getName() {
        return name;
    }

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

}
  • 具体的享元角色
public class TrainTicket extends Ticket{


    public TrainTicket(String from, String to) {
        super(from, to);
    }

    @Override
    public void showTicketInfo(String seat) {
        if (from.equals("北京") && to.equals("青岛")){
            switch (seat){
                case "business":
                    System.out.println(from+"到"+to+getName()+"列车:商务座的价格是988元!");
                    break;
                case "one":
                    System.out.println(from+"到"+to+getName()+"列车:一等座的价格是689元!");
                    break;
                case "two":
                    System.out.println(from+"到"+to+getName()+"列车:二等座的价格是298元!");
                    break;
            }
        }else if (from.equals("北京") && to.equals("济南")){
            switch (seat){
                case "business":
                    System.out.println(from+"到"+to+getName()+"列车:商务座的价格是598元!");
                    break;
                case "one":
                    System.out.println(from+"到"+to+getName()+"列车:一等座的价格是389元!");
                    break;
                case "two":
                    System.out.println(from+"到"+to+getName()+"列车:二等座的价格是186元!");
                    break;
            }
        }

    }
}
  • 享元工厂
    我们以 "出发地-目的地" 为键,存储出票信息的对象,这个是对象得以依赖的标记,就这样,如果缓存中没有这个对象,则创建这个对象,并将对象加入到缓存中,如果有则直接从缓存中取出。
public class TicketFactory {

    // 定义一个池容器
    private static Map<String,Ticket> pool=new HashMap<>();

    // 享元工厂
    public static Ticket getTicket(String from,String to){
        String key=from+"-"+to;
        if (pool.containsKey(key)){
            System.out.println("使用缓存==>"+key);
            return pool.get(key);
        }else {
            System.out.println("创建对象==>"+key);
            Ticket ticket=new TrainTicket(from,to);
            pool.put(key, ticket);
            return ticket;
        }
    }
}
  • 测试代码

       Ticket ticket01=TicketFactory.getTicket("北京","青岛");
       ticket01.showTicketInfo("business");

       Ticket ticket02=TicketFactory.getTicket("北京","青岛");
       ticket02.showTicketInfo("one");

       Ticket ticket03=TicketFactory.getTicket("北京","青岛");
       ticket03.showTicketInfo("two");

       Ticket ticket04=TicketFactory.getTicket("北京","济南");
       ticket04.showTicketInfo("two");
  • 运行结果


从运行结果可以看出,除了第一次是创建的对象以外,其它的都是使用缓存的对象。

四 优缺点

  • 优点:享元模式可以大大减少应用程序创建的对象,降低应用程序内存的占用,增强程序的性能
  • 缺点:享元模式提高了系统的复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化效果,导致系统的逻辑混乱。

五 使用场景

  • 系统中存在大量的相似对象。
  • 细粒度的对象都具备较接近的外部状态,而且内部状态和环境无关。
  • 需要缓冲池的场景。

相关文章

  • 设计模式之享元模式(flyweight模式)

    引入享元模式 享元模式的实例 享元模式的分析 引入享元模式 flyweight是轻量级的意思,指的是拳击比赛中选手...

  • 第4章 结构型模式-享元模式

    一、享元模式的简介 二、享元模式的优缺点 三、享元模式的实例

  • 享元模式

    一、享元模式介绍 二、享元模式代码实例

  • 设计模式--享元模式

    目录 本文的结构如下: 引言 什么是享元模式 模式的结构 典型代码 代码示例 单纯享元模式和复合享元模式 模式扩展...

  • 享元模式C++

    享元模式,就是运用共享技术有效地支持大量细粒度的对象。 享元模式结构图 享元模式基本代码 应用场景 享元模式可以避...

  • 设计模式之——享元模式

    1 享元模式的定义 享元模式:使用共享对象可有效地支持大量细粒度的对象。享元模式是池技术的重要实现方式。享元模式的...

  • 好程序员Java培训​分享java设计模式之享元模式

    好程序员Java培训​分享java设计模式之享元模式,Java设计模式中的享元模式。享元模式有点类似于单例...

  • 结构型模式:享元模式

    文章首发:结构型模式:享元模式 七大结构型模式之六:享元模式。 简介 姓名 :享元模式 英文名 :Flyweigh...

  • Java设计模式(三)

    talk is cheap show me the code 享元模式 享元模式 责任链模式 责任链模式Filte...

  • 结构型-Flyweight

    享元模式原理与实现 享元模式(Flyweight Design Pattern) 所谓“享元”,顾名思义就是被共享...

网友评论

    本文标题:享元模式

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