设计模式之享元模式

享元模式

1.需求

完成内容的不同展示方案

  1. 客户A电脑端发布
  2. 客户B博客发布
  3. 客户C微信公众号发布
2.解决方案
  • 将内容直接复制若干份,然后根据不同的需求进行定制修改
  • 分析
    • 相似的实例对象出现多份,造成资源的冗余和浪费
    • 多份相同或者相似的实例进行维护起来较为麻烦
    • 解决方式:使用享元模式
3.享元模式简单介绍
  • 享元模式:"享"表示共享,"元"表示对象(字面上的意思就是共享对象)

  • 享元模式(Flyweight pattern)也称为蝇量模式:运用共享技术有效复用细粒度对象(避免重复创建对象)

  • 享元模式可以解决 重复对象的内存浪费 问题(假设系统中有大量相似对象,不需要总是创建新对象,可以从建立缓冲池中拿取。这样可以降低系统内存,提高效率)

  • 享元模式中的角色:

    • FlyWeight: 抽象的享元角色,它是产品的抽象类,同时定义出对象的外部状态和内部状态的方法或者实现

      外部状态: 对象得以依赖的标记,随环境改变而改变,不可共享(以下棋为例,类似于棋子的位置)
      内部状态: 对象共享的信息,存储在享元对象内部,不随环境改变而改变(以下棋为例,棋子的颜色)

    • ConcreteFlyWeight: 具体的享元角色,是具体的产品类。实现抽象角色定义的相关业务

    • UnSharedConcreteFlyWeight:不可共享的角色(一般不会出现在享元工厂中)

    • FlyweightFactory:享元工厂类, 用于构建一个池容器(集合),同时提供从池中获取对象的相关方法(一般使用者从内部进行获取对象实例,内部可以使用表结构实现)

  • 享元模式的结构图

在这里插入图片描述

  • 代码详解
package com.liz.GOF23.flyweight;
/**
 * FlyWeight:抽象的享元角色
 * 将外部状态和内部状态进行糅合
 * */
public abstract class WebSite {
    //抽象方法
    public abstract void use(User user);
}

package com.liz.GOF23.flyweight;
/**
 * ConcreteFlyWeight: 具体的享元角色
 * 具体的网站(内部存放类的共有部分)
 * (共同点)
 */
public class ConcreteWebsite extends WebSite {

    //对象共享的信息 内部状态
    private String type = "";//网站发布的形式

    //构造器 传入具体的type
    public ConcreteWebsite(String type) {
        this.type = type;
    }

    @Override
    public void use(User user) {
        System.out.println("网站的用户为"+user.getName()+"  展示类型是" + type);
    }
}

package com.liz.GOF23.flyweight;
import java.util.HashMap;

/**
 * FlyweightFactory:享元工厂类
 */
public class WebSiteFactory {
    //集合,充当池的作用 key: type value: 实例
    private HashMap<String, ConcreteWebsite> pool = new HashMap<>();

    //根据网站的类型,返回一个网站
    public WebSite getWebSiteCategory(String type) {
        //如果没有就创建一个实例,并放入到池中
        if (!pool.containsKey(type)) {
            pool.put(type, new ConcreteWebsite(type));
        }
        //如果存在 直接返回即可
        return pool.get(type);
    }

    //池中数据
    public int getSizeOfPool() {
        return pool.size();
    }
}


package com.liz.GOF23.flyweight;
//外部需要使用的部分
//外部状态(区分点)
public class User {
    private String name;

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

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }
}

package com.liz.GOF23.flyweight;

public class Client {


    public static void main(String[] args) {
        //创建一个工厂
        WebSiteFactory factory = new WebSiteFactory();
        WebSite ByWeChat = factory.getWebSiteCategory("微信");
        WebSite ByBlog = factory.getWebSiteCategory("博客");

        ByBlog.use(new User("客户1"));
        ByWeChat.use(new User("客户2"));
        System.out.println("对象个数:"+factory.getSizeOfPool());
        //复用
        WebSite ByWeChatCopy = factory.getWebSiteCategory("微信");
        ByWeChatCopy.use(new User("客户3"));
        System.out.println("对象个数:"+factory.getSizeOfPool());

    }
}

运行结果:
在这里插入图片描述

注: 在第二次检查对象个数的时候,发现得到的值依旧是2,说明对象的确被复用了。这也是享元模式的核心功能: 在享元模式下,可以避免重复创建相同或者相似的对象,这样可以减少内存和提高程序的效率。此处的缓冲池就是在Factory中定义的Hashmap结构(如果满足key值,就直接返回,否则创建新的值),工业上一般使用UUID作为唯一标识符。

享元模式一些细节
  1. 享元模式使用共享的方式高效支持大量细粒度的对象
  2. 享元模式分离出了外部状态内部状态,以上述代码为例,外部状态为User,内部状态为type,内部状态一般处于具体对象内部,且不可变,外部状态定义在外部且可随着环境可变。所以享元对象可以适配不同的环境
  3. 享元模式的优势:在减少创建对象的同时,减少内存占用和性能的提高
  4. 享元模式的劣势: 要分离出外部状态和内部状态,使得程序逻辑复杂。同时正确分离内部外部状态也并不容易。
  5. 享元模式适用于:
    • 系统存在大量相似对象
    • 系统需要缓冲池时
    • 可以参考String,以及线程池的底层实现
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值