设计模式之享元模式

简介: 在大学时代,估计每个人都去图书馆借过书。借书的流程很简单,如果书架上有这本书直接拿走,到借阅机上借阅就好了,如果没有,可以到图书管理处去拿一本新书。对于整个图书馆来说,书其实就是共享的,但是我们会发现其实每次借的书都是那些破旧一点的书,而不是新书,这是因为学生太多了,如果我们每一次借书都拿出来一本新书,那整个图书馆估计会放不下,对于我们借书的流程和图书共享的方式就是享元模式。

一、认识享元模式


1、概念


如果在一个系统中存在多个相同的对象,那么只需要共享一份对象的拷贝,而不必为每一次使用都创建新的对象。目的是提高系统性能。

上面的概念乍一听好像单例模式其实不是,单例模式只保存一个对象,但是这里可以有很多个不同对象,但是每个对象只有一个实例而已。也就是说享元模式使用了单例模式。


2、例子解释


在文章一开始其实我们就讲了这个例子,现在我们梳理一下,再次用这个例子来解释享元模式。张三去借书,然后阅读完了还回去了,过一段时间发现还是不懂,又去借了同样的书,但是这本书其实和上一次借的书是同一本。李四也去借书,发现书架上没有,就去图书管理员那边拿出来了一本全新的书。这就是享元模式。


享元模式的主要角色由享元工厂、抽象享元、具体享元类几部分组成。

我们使用这个例子以类图的角度来观察一下:

v2-e77d758e061cf9c3ecfb2c2017f454c7_1440w.jpg

从上面这个例子我们可以看到,这里其实有四个角色:


(1)享元工厂(Llibrary):用于创建具体享元类,维护相同的享元对象。当请求对象已经存在时,直接返回对象,不存在时,在创建对象。在例子中的解释就是图书馆,保存了所有的书,当学生借书时,有就拿走,没有买一本新书。这里面其实是使用了单例模式的。


(2)抽象享元(Book):定义需要共享的对象业务接口。享元类被创建出来总是为了实现某些特定的业务逻辑.


(3)具体享元(ConcreteBook):实现抽象享元类的接口,完成某一具体逻辑。在这里表示可以被借出。


在这里享元工厂是享元模式的核心,它需要确保系统可以共享相同的对象。它会维护一个对象列表,当我们想要获取享元类时,如果请求的享元类已经被创建,则直接返回已有的享元类:若没有,则创建一个新的享元对象,并将它加入到维护队列中。

下面我们使用代码来实现一下吧。


二、代码实现


第一步:定义抽象享元类(Book)

public interface Book {
    public void borrow();
}

第二步:定义具体享元类(ConcreteBook)

public class ConcreteBook implements Book {
    //被借出的书名
    private String name;
    public ConcreteBook(String name) {
        this.name = name;
    }
    @Override
    public void borrow() {
        System.out.println("图书馆借出一本书,书名为:" + this.name );
    }
}

第三步:享元工厂(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 libToBorrow(String bookName){
        Book order = null;
        //如果书架有,直接借出
        if (bookPools.containsKey(bookName)) {
            order = bookPools.get(bookName);
        }
        //如果书架没有,那就调进来一本新书
        else{
            order = new ConcreteBook(bookName);
            bookPools.put(bookName, order);
        }
        return order;
    }
    //图书馆书架上的书的数量
    public int getAllBookSize(){
        return bookPools.size();
    }
}

第四步:模拟学生去借书

public class Student {
    //图书馆书架上的书
    private static List<Book> books = new ArrayList<Book>();
    private static Library library;
    public static void main(String[] args) {
        library = Library.getInstance();
        studentBorrow("java编程思想");
        studentBorrow("java核心卷一");
        studentBorrow("java从入门到精通");
        System.out.println("后两本没学会,又借了一次 ");
        studentBorrow("java核心卷一");
        studentBorrow("java从入门到精通");
        //把每一本书借出去
        for (Book book : books) {
            book.borrow();
        }
        //输出一些学生一共借多少本书
        System.out.println("学生一共借了 " + books.size() + " 本书! ");
        //输出一下图书馆一共借出多少本书
        System.out.println("图书馆实际借出" + library.getAllBookSize() + " 本书");
    }
    private static void studentBorrow(String bookName) {
        books.add(library.libToBorrow(bookName));
    }
}

在上面其实学生一共借了5次书,但是有两本是重复的,所以对于图书馆来说,其实是借出去了三本书。最后我们看一下输出结果吧:

//图书馆借出去一本书,书名为:java编程思想
//图书馆借出去一本书,书名为:java核心卷一
//图书馆借出去一本书,书名为:java从入门到精通
//后两本没学会,又借了一次 
//图书馆借出去一本书,书名为:java核心卷一
//图书馆借出去一本书,书名为:java从入门到精通
//学生一共借了 5 本书! 
//图书馆实际借出了 3 本书

以上就是享元模式的代码实现,其实在这里最为关键的就是享元工厂类。享元模式的思想也主要在这个类中去体现。最后我们把享元模式和其他的模式进行一个对比分析。


三、分析享元模式


1、享元模式的优点


(1)节省内存空间,对于可重复的对象只会被创建一次,对象比较多时,就会极大的节省空间。


(2)提高效率,由于创建对象的数量减少,所以对系统内存的需求也减小,使得速度更快,效率更高。


2、享元模式的缺点


其实对于享元类有内部状态和外部状态,其区分就是图书馆的书一部分可以外借(外部状态),一部分不可外借(内部状态),两个状态的划分对于书籍管理来说优点复杂化了。


3、享元模式与单例模式的区别


(1)享元设计模式是一个类有很多对象,而单例是一个类仅一个对象。

(2)享元模式是为了节约内存空间,提升程序性能,而单例模式则主要是出于共享状态的目的。

OK,以上就是享元模式,在使用的时候只需要记住享元模式的核心思想,然后根据自己的业务需求来选择,因为大大多情况下都不会使用一种设计模式,而是多种设计模式的组合。如有问题还请批评指正。

相关文章
|
7月前
|
设计模式 存储 Java
23种设计模式,享元模式的概念优缺点以及JAVA代码举例
【4月更文挑战第6天】享元模式(Flyweight Pattern)是一种结构型设计模式,旨在通过共享技术有效地支持大量细粒度对象的重用。这个模式在处理大量对象时非常有用,特别是当这些对象中的许多实例实际上可以共享相同的状态时,从而可以减少内存占用,提高程序效率
99 4
|
7月前
|
设计模式
二十三种设计模式全面解析-组合模式与享元模式的结合应用:实现对象的共享和高效管理
二十三种设计模式全面解析-组合模式与享元模式的结合应用:实现对象的共享和高效管理
|
3月前
|
设计模式 Java
Java设计模式-享元模式(12)
Java设计模式-享元模式(12)
|
4月前
|
设计模式 存储 Java
【十】设计模式~~~结构型模式~~~享元模式(Java)
文章详细介绍了享元模式(Flyweight Pattern),这是一种对象结构型模式,通过共享技术实现大量细粒度对象的重用,区分内部状态和外部状态来减少内存中对象的数量,提高系统性能。通过围棋棋子的设计案例,展示了享元模式的动机、定义、结构、优点、缺点以及适用场景,并探讨了单纯享元模式和复合享元模式以及与其他模式的联用。
【十】设计模式~~~结构型模式~~~享元模式(Java)
|
5月前
|
设计模式 存储 JavaScript
js设计模式【详解】—— 享元模式
js设计模式【详解】—— 享元模式
67 6
|
6月前
|
设计模式 缓存 Java
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
Java设计模式:享元模式实现高效对象共享与内存优化(十一)
|
6月前
|
设计模式 存储 Java
Java设计模式之享元模式详解
Java设计模式之享元模式详解
|
6月前
|
设计模式
享元模式-大话设计模式
享元模式-大话设计模式
|
7月前
|
设计模式 Go
[设计模式 Go实现] 结构型~享元模式
[设计模式 Go实现] 结构型~享元模式
|
7月前
|
设计模式 存储 Java
小谈设计模式(27)—享元模式
小谈设计模式(27)—享元模式