大话设计模式十六:享元模式

一.模式定义

享元模式(Flyweight Pattern):运用共享技术有效地支持大量细粒度对象的复用。系统只使用少量的对象,而这些对象都很相似,状态变化很小,可以实现对象的多次复用。
Flyweight Pattern: Use sharing to support large numbers of fine-grained objects efficiently. 

 

二.模式要素
Flyweight: 抽象享元类
ConcreteFlyweight: 具体享元类
UnsharedConcreteFlyweight: 非共享具体享元类
FlyweightFactory: 享元工厂类

 

三.举例说明

大话设计模式十六:享元模式_第1张图片

享元模式的本质是为了实现大量细粒度对象的复用。

要想实现这样的功能就需要一个享元池,如果该元素已经在池子中有了直接拿出来用,不需要新建。如果元素在池中没有才需要新建。

假设有工厂代工手机生产,代工完出厂的手机都有其对应的价格,需要对外展示各种品牌手机的出厂价格。假设该工厂可以代工华为手机,也可以代工苹果手机。如果一旦代工了某种品牌的手机,该工厂的享元池就增加了一个元素,查询该品牌的手机信息就直接从池子里拿。如果该工厂从来没代工过某手机,就在享元池里新建一个元素,之后可以获取相关的信息。这样的功能借助享元模式的思路是很好实现的。

 

四.具体代码

IProduct.java    产品接口

package flyweightPattern;

/**
 * 描述:
 * 产品接口
 *
 * @author Lei Dong
 * @create 2019-04-29 10:14
 */
public abstract class IProduct {
    public String name;

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

    abstract int obtainPrice();

    abstract String showName();
}

HuaWeiMobile.java  华为手机

package flyweightPattern;

/**
 * 描述:
 * 华为手机
 *
 * @author Lei Dong
 * @create 2019-04-29 10:15
 */
public class HuaWeiMobile extends IProduct {
    public HuaWeiMobile() {
        super("huawei");
    }

    @Override
    public int obtainPrice() {
        return 5000;
    }

    @Override
    String showName() {
        return name;
    }
}

AppleMobile.java  苹果手机

package flyweightPattern;

/**
 * 描述:
 * 苹果手机
 *
 * @author Lei Dong
 * @create 2019-04-29 13:59
 */
public class AppleMobile extends IProduct {
    public AppleMobile() {
        super("apple");
    }

    @Override
    int obtainPrice() {
        return 8000;
    }

    @Override
    String showName() {
        return name;
    }
}

ProductPool.java  产品池

package flyweightPattern;

import java.util.HashMap;

/**
 * 描述:
 * 产品池
 *
 * @author Lei Dong
 * @create 2019-04-29 10:22
 */
public class ProductPool {
    private static HashMap productPool = new HashMap<>();

    public static IProduct obtainProducts(String name) {
        if (productPool.containsKey(name)) {
            return productPool.get(name);
        } else {
            IProduct product = null;
            if (name.equalsIgnoreCase("huawei")) {
                product = new HuaWeiMobile();
            }
            if (name.equalsIgnoreCase("apple")) {
                product = new AppleMobile();
            }
            productPool.put(name, product);
            return productPool.get(name);
        }
    }

    public static int obtainSize() {
        return productPool.size();
    }
}

Main.java  

package flyweightPattern;

/**
 * 描述:
 * Main  享元模式
 *
 * @author Lei Dong
 * @create 2019-04-29 10:14
 */
public class Main {
    public static void main(String[] args) {
        System.out.println();

        IProduct products1 = ProductPool.obtainProducts("huawei");
        System.out.println(products1.showName() + "  :  " + products1.obtainPrice());
        System.out.println("Pool size:" + ProductPool.obtainSize());

        IProduct products2 = ProductPool.obtainProducts("apple");
        System.out.println(products2.showName() + "  :  " + products2.obtainPrice());
        System.out.println("Pool size:" + ProductPool.obtainSize());

        IProduct products3 = ProductPool.obtainProducts("huawei");
        System.out.println(products3.showName() + "  :  " + products3.obtainPrice());
        System.out.println("Pool size:" + ProductPool.obtainSize());
    }
}

运行结果:

大话设计模式十六:享元模式_第2张图片

可以看到之前塞进产品池华为手机,之后再次调用华为手机的属性时并没有新建元素,而是复用了已有的元素。

 

五.总结

1.享元模式的优点
(1)享元模式的优点在于它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份。
(2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。

2.享元模式的缺点
(1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化。
(2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。

3.模式适用场景
在以下情况下可以使用享元模式:
(1)一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
(2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
(3)使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。

你可能感兴趣的:(设计模式)