享元模式分析与实践


享元就是共享单元(元素)的意思。单元代表了整体的部分,如果一个对象其中的部分是稳定的不会改变的,那么这个部分即可以共享。享元模式的用途就是复用对象的单元,让对象的节省内存。

一、享元模式与单例模式区别

单例模式是类级别的,一个类只能有一个对象实例;
享元模式是对象级别的,可以有多个对象实例,多个变量引用同一个对象实例;
享元模式主要是为了节约内存空间,提高系统性能,而单例模式主要为了可以共享数据;

1、优点

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

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

2、缺点

提高了系统复杂性,需要分离出外部状态(k)和内部状态(v),而且外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统的逻辑混乱,为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。

● 内部状态

内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变,它们可以作为一个对象的动态附加信息,不必直接储存在具体某个对象中,属于可以共享的部分。

● 外部状态

外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态,它是一批对象的统一标识,是唯一的一个索引值。

3、享元模式在jdk中的体现

1.1String中的intern()方法

public static void main(String[] args) {
        String str1 = "法外狂徒";
        String str2 = "张三";
        String str3 = "法外狂徒张三";
        String str4;
        str4 = str1 + str2;
        System.out.println(str3 == str4);
		//如果是String的对象池中有该类型的值,则直接返回对象池中的对象
        str4 = (str1 + str2).intern();
        System.out.println(str3 == str4);
}

输出结果:false true

1.2Integer中的vauleOf()方法

在范围[-128, 127]内在Integer缓存中直接取,范围外通过new Integer(i) 生成

        //Integer中的缓存数组 cache
	    Integer[] cache = new Integer[(high - low) + 1];
        int j = low;
        for(int k = 0; k < cache.length; k++)
            cache[k] = new Integer(j++);
 
		public static Integer valueOf(int i) {
                if (i >= IntegerCache.low && i <= IntegerCache.high)
                    return IntegerCache.cache[i + (-IntegerCache.low)];
                return new Integer(i);
       	 }
        Integer i1 = Integer.valueOf(99);
        Integer i2 = Integer.valueOf(99);
        System.out.println(i1==i2);
        Integer i3 = Integer.valueOf(128);
        Integer i4 = Integer.valueOf(128);
        System.out.println(i3==i4);

输出结果:true false

二、享元模式与单例模式代码举例

1.1单例模式代码

public class Singleton {
    // 我来写一个单例模式  懒汉式
    private static Singleton singleton;
    private Singleton(){}
    
    public static synchronized Singleton getSingleton(){
        if(singleton==null){
            singleton=new Singleton();
        }
        return singleton;
    }
    public static void main(String[] args) {
        Singleton instance1 = Singleton.getSingleton();
        Singleton instance2 = Singleton.getSingleton();
        System.out.println(instance1==instance2);
    }
}

1.2享元模式代码

定义抽象享元类

/**
 * 定义抽象享元类
 */
public abstract class Book {

    /**
     * 外部状态 书名
     */
    public String name;

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

    /**
     * 借书动作
     */
    public abstract void borrow();
}

定义具体享元类

/**
 * 定义具体享元类
 */
public class ConcreteBook extends Book {

    /**
     * 被借出的书名
     */
    public ConcreteBook(String name){
        super(name);
    }

    @Override
    public void borrow() {
        System.out.println("借了一本书名为:"+this.name);
    }
}

享元工厂

/**
 * 享元工厂
 */
public class LibraryFactory {

    /**
     * 图书馆维护一个图书列表
     */
    private Map<String, Book> bookPools = new HashMap<>();

    private static LibraryFactory factory = new LibraryFactory();

    /**
     * 图书馆只有一个
     */
    public static LibraryFactory getInstance() {
        return factory;
    }

    /**
     * 图书馆外借图书
     */
    public Book libToBorrow(String bookName) {
        Book order;
        //如果书架有书,直接借出
        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();
    }
}

控制层

@RestController
@RequestMapping("/studentController")
public class StudentController {

    /**
     * 图书馆书架上的书
     */
    private static List<Book> books = new ArrayList<>();
    private static LibraryFactory libraryFactory;

    /**
     * 查询
     */
    @PostMapping("/borrow")
    @ResponseBody
    public void borrow() {
        libraryFactory = LibraryFactory.getInstance();
        studentBorrow("葵花宝典");
        studentBorrow("僻邪剑谱");
        studentBorrow("java从入门到放弃");
        //把每一本书借出去
        for (Book book : books) {
            book.borrow();
        }
        System.out.println("===========================后两本秘籍没学会,又借了一次 ");
        studentBorrow("僻邪剑谱");
        studentBorrow("java从入门到放弃");

        Book piXieJianPu = libraryFactory.libToBorrow("僻邪剑谱");
        piXieJianPu.borrow();
        Book ruMenFangQi = libraryFactory.libToBorrow("java从入门到放弃");
        ruMenFangQi.borrow();

        //输出一些学生一共借多少本书
        System.out.println("学生一共借了 " + books.size() + " 本书! ");
        //输出一下图书馆一共借出多少本书
        System.out.println("图书馆实际借出" + libraryFactory.getAllBookSize() + " 本书");
    }

    /**
     * 学生借书,将借的书,记录到图书馆书架列表
     */
    private static void studentBorrow(String bookName) {
        books.add(libraryFactory.libToBorrow(bookName));
    }
}

三、项目结构及测试结果

在这里插入图片描述

源码地址SpringBoot2.XLearn 欢迎star
测试结果
在这里插入图片描述
在结果中可以看出:其实学生一共借了5次书,但是有两本是重复的,所以对于图书馆来说,其实是借出去了三本书。
在这里插入图片描述
参考资料
设计模式—享元模式
设计模式之享元模式
享元模式与单例模式区别

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
很抱歉,根据提供的引用内容中没有包含java享元模式的UML图。但是可以为您简要介绍java享元模式的UML图。 享元模式的UML图如下所示: - Flyweight:享元接口,定义了享元对象的公共方法。 - ConcreteFlyweight:具体享元对象,实现了享元接口,并存储了内部状态。 - UnsharedConcreteFlyweight:非共享具体享元对象,不共享的对象,一般不会出现在享元工厂中。 - FlyweightFactory:享元工厂类,负责创建和管理享元对象。 - Client:客户端类,通过享元工厂获取享元对象,并操作具体享元对象。 请注意,由于无法直接提供UML图,以上是一份简化的描述。在实际应用中,可能还会有其他的类和关系。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [Java设计模式之享元模式(UML类图分析+代码详解)](https://blog.csdn.net/m0_51750419/article/details/127332662)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] - *3* [设计模式-享元模式](https://blog.csdn.net/qq_44065088/article/details/108725714)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_1"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值