设计模式——享元模式

177 阅读4分钟

定义:

如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝而不必为每一次使用都创建新的对象。目的是提高系统性能。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象

使用场景:

当一个系统中存在大量重复的对象的时候,而且这些对象是不可变的,可以使用享元模式只保留一分实例,供其他业务使用,可以减少对象在内存中的占用。String常量池、数据库连接池、缓冲池等等都是享元模式的应用,所以说享元模式是池技术的重要实现方式。

优点:

节省内存空间,对于可重复的对象只会被创建一次,对象比较多时,就会极大的节省空间。 提高效率,由于创建对象的数量减少,所以对系统内存的需求也减小,使得速度更快,效率更高。

缺点:

  • 为了使对象可以共享,享元模式需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。

代码实例+场景复现:

假如我们开了一家书店,我们进了4种书,分别是《三国演义》、《红楼梦》、《水浒传》、《西游记》,数量分别是30、40、60、70。那我们需要生成200个对象,其中一部分内容可以通过享元模式共享。

// 第一步:定义抽象享元类(Book)
public interface Book {
    public String getName();

    public String getIntroduction();
}
// 第二步:定义具体享元类(ConcreteBook)
public class ConcreteBook implements Book {
    private String name; // 书名
    private String introduction; // 简介

    public ConcreteBook(String name, String introduction) {
        this.name = name;
        this.introduction = introduction;
    }

    @Override
    public String getName() {
        return this.name;
    }

    @Override
    public String getIntroduction() {
        return this.introduction;
    }
}
// 第三步:享元工厂(Llibrary)
public class Library {
    // 书店采购书籍的种类
    private Map<String, Book> bookPools = new HashMap<String, Book>();
    private static Library factory = new Library();

    // 书店只有一个
    public static Library getInstance() {
        return factory;
    }

    // 采购图书
    public Book purchaseBook(String bookName, String introduction) {
        Book book = null;
        // 如果书店有
        if (bookPools.containsKey(bookName)) {
            book = bookPools.get(bookName);
        } else { // 如果没有,那就是一本新书
            book = new ConcreteBook(bookName, introduction);
            bookPools.put(book.getName(), book);
        }
        return book;
    }

    // 采购的图书种类数量
    public int getAllBookSize() {
        return bookPools.size();
    }
}
// 第四部:定义实际书籍类
public class SpecificBook {
    private Book book;
    private String id;

    public SpecificBook(Book book, String id) {
        this.book = book;
        this.id = id;
    }

    public Book getBook() {
        return this.book;
    }

    public String getId() {
        return this.id;
    }
}
// 第五步:采购书籍
public class Bookstore {
    // 书店上的书
    private static List<SpecificBook> specificBooks = new ArrayList<SpecificBook>();
    private static Library library;

    public static void main(String[] args) {
        library = Library.getInstance();
        // 我们进了4种书,分别是《三国演义》、《红楼梦》、《水浒传》、《西游记》,数量分别是30、40、60、70
        Book book = library.purchaseBook("三国演义", "元末明初小说家罗贯中根据陈寿《三国志》和裴松之注解以及" +
                "民间三国故事传说经过艺术加工创作而成的长篇章回体历史演义小说");
        for (int index = 0; index < 30; index++) {
            SpecificBook specificBook = new SpecificBook(book, "sgyy" + index);
            specificBooks.add(specificBook);
        }
        book = library.purchaseBook("红楼梦", "小说以贾、史、王、薛四大家族的兴衰为背景,以富贵公子" +
                "贾宝玉为视角,以贾宝玉与林黛玉、薛宝钗的爱情婚姻悲剧为主线,描绘了一些闺阁佳人的人生百态");
        for (int index = 0; index < 40; index++) {
            SpecificBook specificBook = new SpecificBook(book, "hlm" + index);
            specificBooks.add(specificBook);
        }
        book = library.purchaseBook("水浒传", "元末明初小说家罗贯中根据陈寿《三国志》和裴松之注解以及" +
                "民间三国故事传说经过艺术加工创作而成的长篇章回体历史演义小说");
        for (int index = 0; index < 60; index++) {
            SpecificBook specificBook = new SpecificBook(book, "xhzh" + index);
            specificBooks.add(specificBook);
        }
        book = library.purchaseBook("西游记", "小说主要讲述了孙悟空出世跟随菩提祖师学艺及大闹天宫后," +
                "遇见了唐僧、猪八戒、沙僧和白龙马,西行取经,一路上历经艰险,降妖除魔,经历了九九八十一难,终于到达西天见到如来佛祖,最终五圣成真的故事");
        for (int index = 0; index < 70; index++) {
            SpecificBook specificBook = new SpecificBook(book, "xyj" + index);
            specificBooks.add(specificBook);
        }

        // 输出书店采购了多少本书
        System.out.println("书店总共采购 " + specificBooks.size() + " 本书! ");
        // 输出一下书店有几种书
        System.out.println("书店有" + library.getAllBookSize() + " 种书");

        // 取第一本书和第二本书(都是三国演义),证明他们确共享了book
        SpecificBook specificBook1 = specificBooks.get(0);
        SpecificBook specificBook2 = specificBooks.get(1);
        System.out.println("它们是否共享了数据:" + (System.identityHashCode(specificBook1.getBook()) +" " + System.identityHashCode(specificBook2.getBook())));

        // 顾客随机购买了一本书
        SpecificBook specificBook = specificBooks.remove(44);
        // 输出顾客买了什么
        System.out.println(
                "顾客购买了《" + specificBook.getBook().getName() + "》 简介:" + specificBook.getBook().getIntroduction()
                        + " 书籍编号:" + specificBook.getId());

        // 输出书店剩余了多少本书
        System.out.println("书店剩余 " + specificBooks.size() + " 本书! ");
    }

}

在上面的例子中,书店一共采购了200本书籍,但只有4个种类。

书店总共采购 200 本书! 
书店有4 种书
它们是否共享了数据:366712642 366712642
顾客购买了《红楼梦》 简介:小说以贾、史、王、薛四大家族的兴衰为背景,以富贵公子贾宝玉为视角,以贾宝玉与林黛玉、薛宝钗的爱情婚姻悲剧为主线,描绘了一些闺阁佳人的人生百态 书籍编号:hlm14
书店剩余 199 本书!