设计模式—享元模式

一、什么是享元模式

享元模式通过共享技术有效地支持细粒度、状态变化小的对象复用,当系统中存在有多个相同的对象,那么只共享一份,不必每个都去实例化一个对象,极大地减少系统中对象的数量。

比如当前电商项目中在购物车中,可能会有多个相同商品的实例被加入到购物车中,这些商品的信息可能相似。通过享元模式可以共享相同商品的信息对象,减少购物车中的内存消耗。

在了解享元模式之前我们先要了解两个概念:内部状态、外部状态。

  • 内部状态:在享元对象内部不随外界环境改变而改变的共享部分。
  • 外部状态:随着环境的改变而改变,不能够共享的状态就是外部状态。

由于享元模式区分了内部状态和外部状态,所以我们可以通过设置不同的外部状态使得相同的对象可以具备一些不同的特性,而内部状态设置为相同部分。在我们的程序设计过程中,我们可能会需要大量的细粒度对象来表示对象,如果这些对象除了几个参数不同外其他部分都相同,这个时候我们就可以利用享元模式来大大减少应用程序当中的对象。如何利用享元模式呢?这里我们只需要将他们少部分的不同的部分当做参数移动到类实例的外部去,然后再方法调用的时候将他们传递过来就可以了。这里也就说明了一点:

内部状态存储于享元对象内部,而外部状态则应该由客户端来考虑。

三、代码案例:

场景:假如在电商网站的购物车中,对于一些多个相同的商品实例,这些商品信息可能相似,那么就可以共享一些信息对象,减少内存消耗。

首先是抽象类

复制代码
public  abstract class showPhone {

    public abstract void getPid();  //获取商品pid 只有商品pid不同
}

然后是实现类

复制代码
public class XmPhone extends showPhone{

    private String pid;

    public XmPhone(String pid){
        this.pid=pid;
    }


    @Override
    public void getPid() {
        System.out.println(pid);
    }

    public void setPid(String pid){
        this.pid=pid;
    }
}

再是享元工厂类

复制代码
public class showPhoneFactory {

    static HashMap<String,showPhone> hashMap=new HashMap<>();


    public static showPhone getPhone(String key){
        showPhone showPhone=hashMap.get(key);

        if (showPhone==null){
            showPhone=new XmPhone(key); //如果没有则新建一个
            hashMap.put(key,showPhone);//然后放入池中
        }
        return showPhone;
    }



    public void getSize(){
        int size = hashMap.size();
        System.out.println(size);
    }
}

在这里定义了一个HashMap 用来存储各个对象,用户需要对象时,首先从享元池中获取,如果享元池中不存在,则创建一个新的享元对象返回给用户,并在享元池中保存该新增对象。

客户端

复制代码
public class Test {
    public static void main(String[] args) {
        showPhone phone = showPhoneFactory.getPhone("123");
        System.out.println(phone);

        showPhone phone2 = showPhoneFactory.getPhone("666");
        System.out.println(phone2);

        showPhone phone3 = showPhoneFactory.getPhone("123");
        System.out.println(phone3);
        System.out.println(phone3==phone);

    }
}
//运行结果
com.patterns.flyWeight.XmPhone@396f6598
com.patterns.flyWeight.XmPhone@394e1a0f
com.patterns.flyWeight.XmPhone@396f6598
true

在 Java 中,String 类型就是使用享元模式,String 对象是 final 类型,对象一旦创建就不可改变。而 Java 的字符串常量都是存在字符串常量池中的,JVM 会确保一个字符串常量在常量池中只有一个拷贝。

四、享元模式的优缺点:

1、享元模式的优点:

(1)极大减少系统中对象的个数;

(2)由于使用了外部状态,外部状态相对独立,不会影响到内部状态,所以享元模式使得享元对象能够在不同的环境被共享。

2、享元模式的缺点:

(1)由于享元模式需要区分外部状态和内部状态,使得应用程序在某种程度上来说更加复杂化了。

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

3、适用场景:

(1)如果系统中存在大量的相同或者相似的对象,由于这类对象的大量使用,会造成系统内存的耗费,可以使用享元模式来减少系统中对象的数量。

(2)对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。

相关推荐
ytadpole4 分钟前
Spring Cloud Gateway:一次不规范 URL 引发的路由转发404问题排查
java·后端
华仔啊13 分钟前
基于 RuoYi-Vue 轻松实现单用户登录功能,亲测有效
java·vue.js·后端
程序员鱼皮44 分钟前
刚刚 Java 25 炸裂发布!让 Java 再次伟大
java·javascript·计算机·程序员·编程·开发·代码
闰五月1 小时前
JavaScript执行上下文详解
面试
浮游本尊1 小时前
Java学习第21天 - 微服务架构设计
java
烛阴1 小时前
【TS 设计模式完全指南】懒加载、缓存与权限控制:代理模式在 TypeScript 中的三大妙用
javascript·设计模式·typescript
渣哥1 小时前
Java CyclicBarrier 详解:原理、使用方式与应用场景
java
Lotzinfly1 小时前
8 个经过实战检验的 Promise 奇淫技巧你需要掌握😏😏😏
前端·javascript·面试
知其然亦知其所以然1 小时前
MySQL 社招必考题:如何优化查询过程中的数据访问?
后端·mysql·面试