设计模式-享元模式

享元模式是一种有效地支持大量细粒度对象复用的技术,通过共享已有对象减少内存消耗。该模式结合了工厂方法和单例模式的特点,通过享元工厂管理可共享的享元对象。典型应用包括图书馆借书系统和汽车工厂,通过存储共享对象,如书籍和汽车,减少资源占用。

享元模式

享元模式介绍

定义

运用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。

优点

  • 如果系统有大量类似的对象,开会节省大量的内存及CPU资源

典型案例

  • StringIntegerLong
  • com.sun.org.apache.bcel.internal.generic.InstructionConstants

享元模式结构与实现

其实享元模式好比 工厂方法模式 和 单例模式 的结合。
使用工厂创建实例,如果实例存在则直接返回不再创建(单例)。对于每个指定享元内容的对象存在唯一实例。

结构

抽象享元角色(Flyweight):是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
**具体享元(Concrete Flyweight)**角色:实现抽象享元角色中所规定的接口。
非享元(Unsharable Flyweight)角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
享元工厂(Flyweight Factory)角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。
在这里插入图片描述

模板实现

import java.util.HashMap;

/**
 * 非享元角色
 */
class UnsharedConcreteFlyweight {
    private String info;
    UnsharedConcreteFlyweight(String info) {
        this.info = info;
    }
    public String getInfo() {
        return info;
    }
    public void setInfo(String info) {
        this.info = info;
    }
}

/**
 * 抽象享元角色
 */
interface Flyweight {
    void operation(UnsharedConcreteFlyweight state);
}

/**
 * 具体享元角色
 */
class ConcreteFlyweight implements Flyweight {
    private String key;
    ConcreteFlyweight(String key) {
        this.key = key;
        System.out.println("具体享元[" + key + "]被创建!");
    }
    @Override
    public void operation(UnsharedConcreteFlyweight outState) {
        System.out.print("具体享元[" + key + "]被调用,");
        System.out.println("非享元信息是:[" + outState.getInfo() + "]");
    }
}
/**
 * 享元工厂角色
 */
class FlyweightFactory {
    private HashMap<String, Flyweight> flyweights = new HashMap<String, Flyweight>();
    public Flyweight getFlyweight(String key) {
        Flyweight flyweight = flyweights.get(key);
        if (flyweight != null) {
            System.out.println("具体享元[" + key + "]已经存在,被成功获取!");
        } else {
            flyweight = new ConcreteFlyweight(key);
            flyweights.put(key, flyweight);
        }
        return flyweight;
    }
}

/**
 * 客户端角色
 */
public class FlyWeightClient {
    public static void main(String[] args) {
        FlyweightFactory factory = new FlyweightFactory();
        Flyweight fa1 = factory.getFlyweight("a");
        Flyweight fa2 = factory.getFlyweight("a");
        Flyweight fa3 = factory.getFlyweight("a");
        Flyweight fb1 = factory.getFlyweight("b");
        Flyweight fb2 = factory.getFlyweight("b");
        Flyweight fb3 = factory.getFlyweight("b");
        fa1.operation(new UnsharedConcreteFlyweight("第1次调用a。"));
        fa2.operation(new UnsharedConcreteFlyweight("第2次调用a。"));
        fa3.operation(new UnsharedConcreteFlyweight("第3次调用a。"));
        fb1.operation(new UnsharedConcreteFlyweight("第1次调用b。"));
        fb2.operation(new UnsharedConcreteFlyweight("第2次调用b。"));
        fb3.operation(new UnsharedConcreteFlyweight("第3次调用b。"));
    }
}

Client运行结果

具体享元[a]被创建!
具体享元[a]已经存在,被成功获取!
具体享元[a]已经存在,被成功获取!
具体享元[b]被创建!
具体享元[b]已经存在,被成功获取!
具体享元[b]已经存在,被成功获取!
具体享元[a]被调用,非享元信息是:[第1次调用a。]
具体享元[a]被调用,非享元信息是:[第2次调用a。]
具体享元[a]被调用,非享元信息是:[第3次调用a。]
具体享元[b]被调用,非享元信息是:[第1次调用b。]
具体享元[b]被调用,非享元信息是:[第2次调用b。]
具体享元[b]被调用,非享元信息是:[第3次调用b。]

示例 图书馆借书

我们只需要存储借用过的书籍信息,无论多少用户借用书籍,书籍的内容都可以通过享元模式存放访问,极大的节省内存空间。

Flyweight: 书籍
Concrete Flyweight: 书籍实现类
Unsharable Flyweight: 借阅者姓名
Flyweight Factory: 图书馆

import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 抽象享元角色:书籍
 */
interface Book {
    /**
     * 借阅书籍
     * @param name 借阅人姓名
     */
    void borrow(String name);
}

/**
 * 具体享元角色:具体书籍
 */
class BookConcrete implements Book{
    private final String bookName;

    BookConcrete(String bookName) {
        System.out.println("创建了书籍:" + bookName);
        this.bookName = bookName;
    }

    @Override
    public void borrow(String name) {
        System.out.println(bookName + "已被[" + name + "]借出");
    }
}

/**
 * 享元工厂角色:图书馆
 */
class Library {
    HashMap<String, Book> books = new HashMap<>();

    public Book getBook(String bookName) {
        Book book = books.get(bookName);
        if (book == null) {
            // 如果书籍不存在则引进这种书到图书馆
            book = new BookConcrete(bookName);
            books.put(bookName, book);
        }
        return book;
    }

    public int getDiffBookNumber() {
        return books.size();
    }

}

public class BookFlyWeightClient {
    public static void main(String[] args) {
        final Library library = new Library();
        library.getBook("鲁滨逊漂流记").borrow("张三");
        library.getBook("鲁滨逊漂流记").borrow("李四");
        library.getBook("鲁滨逊漂流记").borrow("王五");
        library.getBook("西游记").borrow("老六");
        library.getBook("西游记").borrow("张三");
        library.getBook("西游记").borrow("阿七");

        System.out.println(library.getDiffBookNumber());
    }
}

运行结果

创建了书籍:鲁滨逊漂流记
鲁滨逊漂流记已被[张三]借出
鲁滨逊漂流记已被[李四]借出
鲁滨逊漂流记已被[王五]借出
创建了书籍:西游记
西游记已被[老六]借出
西游记已被[张三]借出
西游记已被[阿七]借出
2

示例2 汽车工厂,每种车子最多只造一辆,重复使用

每种车子只造(工厂方法)一次(单例),后续使用同种车子都是同一辆车来运输!!!

import java.util.HashMap;

/**
 * 抽象享元角色:车
 */
interface Car {
    /**
     * 运输货物
     */
    void transport();
}

/**
 * 具体享元角色:拖拉机
 */
class Tractor implements Car {
    @Override
    public void transport() {
        System.out.println("拖拉机运输");
    }
}

/**
 * 具体享元角色:汽车
 */
class Automobile implements Car {
    @Override
    public void transport() {
        System.out.println("汽车运输");
    }
}

/**
 * 具体享元角色:火车
 */
class Train implements Car {
    @Override
    public void transport() {
        System.out.println("火车运输");
    }
}

/**
 * 享元工厂:汽车工厂
 */
class CarFactory {
    private HashMap<String, Car> cars = new HashMap<>();
    Car getCar(String carName) {
        Car car = cars.get(carName);
        if (car == null) {
            switch (carName) {
                case "火车":car = new Train();break;
                case "拖拉机":car = new Tractor();break;
                case "汽车":car = new Automobile();break;
                default: return null;
            }
            System.out.println("创建了:" + carName);
            cars.put(carName, car);
        }
        System.out.println("获取了:"+carName);
        return car;
    }
}

/**
 * 每种车子只造(工厂方法)一次(单例),后续使用同种车子都是同一个车子
 */
public class CarFlyWeight {
    public static void main(String[] args) {
        final CarFactory carFactory = new CarFactory();
        carFactory.getCar("汽车").transport();
        carFactory.getCar("汽车").transport();
        carFactory.getCar("拖拉机").transport();
        carFactory.getCar("拖拉机").transport();
        carFactory.getCar("火车").transport();
        carFactory.getCar("火车").transport();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值