design pattern · 2020-02-09 0

Java设计模式-享元模式

一、概述

享元模式(Flyweigh),也叫蝇量模式:运行共享技术有效地支持大量细粒度的对象。针对系统中存在的大量重复对象,享元模式通过减少重复对象创建的数量,来减少内存占用和提高性能。

享元模式的核心是:共享与分离,共享对象中不变的部分,分离对象中可变的部分。享元对象能做到共享的关键是区分内蕴状态和外蕴状态。所谓共享,即多个对象内部的状态应当是一样的,否则就谈不上共享。

内蕴状态是存储在享元对象内部的,并且是不会随环境的改变而有所不同。因此,一个享元可以具有内蕴状态并可以共享。

外蕴状态是随环境的改变而改变的、不可以共享的。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候在传入享元对象内部。外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。

二、角色

抽象享元(Flyweight)角色:给出一个抽象接口,以规定出所有具体享元角色需要实现的方法

具体享元(ConcreteFlyweight)角色:实现抽象享元角色所规定出的接口。如果有内蕴状态,必须负责为内蕴状态提供存储空间

享元工厂(FlyweightFactory)角色:本负责创建和管理享元角色。当客户端对象调用一个享元对象的时候,享元工厂会检查系统中是否已经有一个符合要求的享元对象。如果已经有,享元工厂就提供这个已有的享元对象;如果没有,享元工厂就创建一个享元对象

三、享元模式

包含抽象享元角色、具体享元角色、享元工厂

1 抽象享元

public interface NaviInfo {
    void showNaviInfo(String navitype);
}

2 具体享元

public class ConcreteNaviInfo implements NaviInfo {
    /**
     * 内蕴状态
     */
    private String from, dest;

    public ConcreteNaviInfo(String from, String dest) {
        this.from = from;
        this.dest = dest;
    }

    /**
     * navitype是外蕴状态,不影响内蕴状态
     */
    @Override
    public void showNaviInfo(String navitype) {
        if (navitype.equals("taxi")) {
            System.out.println(String.format("%s to %s - an hour - taxi", from, dest));
        } else if (navitype.equals("bus")) {
            System.out.println(String.format("%s to %s - two hours - bus", from, dest));
        }
    }
}

3 享元工厂

public class NaviTypeFactory {
    private static Map<String, NaviInfo> map = new HashMap<>();

    public static NaviInfo getNaviInfo(String from, String dest) {
        String key = from + "-" + dest;
        if (map.containsKey(key)) {
            System.out.println("use cache object");
            return map.get(key);
        } else {
            System.out.println("create new object");
            NaviInfo naviInfo = new ConcreteNaviInfo(from, dest);
            map.put(key, naviInfo);
            return naviInfo;
        }
    }
}

4 测试

public class Client {

    public static void main(String[] args) {
        NaviInfo naviInfo1 = NaviTypeFactory.getNaviInfo("A", "B");
        naviInfo1.showNaviInfo("taxi");
        NaviInfo naviInfo2 = NaviTypeFactory.getNaviInfo("A", "B");
        naviInfo2.showNaviInfo("bus");
    }
}

5 结果

result