4

软件设计模式白话文系列(十一)享元模式 - Eajur

 1 year ago
source link: https://www.cnblogs.com/eajur/p/16895857.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

以共享的方法高效地支持大量细粒度对象的复用。在 Java 中,通过提前初始化对象或者首次使用后记录对象,后续使用就可以复用对象来实现享元模式。类似缓存技术。

2、模式结构

  • 享元对象:可复用对象。

  • 享元工厂类:享元对象的工厂类,负责创建、储存享元对象。客户端从工厂类请求对象有则返回,没有则创建

    一个放入工厂类。例如 String 类的缓存池和数据库的连接池。

3、实现逻辑

享元模式实现的关键是需要区分对象的内蕴状态和外蕴状态。简单点解释就是,内蕴状态就是可被共享的部分;外蕴状态就是不可共享的部分,需要客户端提供的部分。Java 中实现享元模式,就是把内蕴部分剥离出来静态化,客户端调用时提供外蕴状态(当然对象可以没有外蕴部分)。

4、实战代码

RBAC 模型基于角色的权限控制。通过角色关联用户,角色关联权限的方式间接赋予用户权限。

我们知道对于用户来讲,每个用户都有自己的 编号、姓名,但是会存在多个用户都是同一个角色。在这里编号、姓名就属于外蕴状态,而角色就属于内蕴状态。

/**
 * 享元对象
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-15 19:01:20
 */
@Data
public class Role {
    private String name;

    private List<String> permissions;
}

/**
 * 业务对象
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-15 19:00:57
 */
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Member {

    private Long id;
    private String name;

    private Role role;
}

/**
 * 享元工厂类
 * 这里结合静态内部类单例模式实现 RoleFactory
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-15 19:04:47
 */
public class RoleFactory {
    private static Map<String, Role> roleMap = new HashMap<>();

    public RoleFactory() {
        Role admin = new Role();
        admin.setName("admin");
        admin.setPermissions(List.of("add", "update", "select", "delete"));

        Role user = new Role();
        user.setName("user");
        user.setPermissions(List.of("select"));

        roleMap.put("admin", admin);
        roleMap.put("user", user);
    }

    public Role getRole(String name) {
        return roleMap.get(name);
    }

    public static final RoleFactory getInstance() {
        return SingletonHolder.INSTANCE;
    }

    private static class SingletonHolder {
        private static final RoleFactory INSTANCE = new RoleFactory();
    }
}

/**
 * 测试类
 *
 * @author Eajur.Wen
 * @version 1.0
 * @date 2022-11-15 19:13:48
 */
public class Client {
    public static void main(String[] args) {
        // 创建 10 个 Admin 用户
        for (int i = 0; i < 10; i++) {
            Member member = new Member((long) i,
                    "admin" + i,
                    RoleFactory.getInstance().getRole("admin"));
            System.out.println(member);
        }
        System.out.println("------------------");
        // 创建 100 个 User 用户
        for (int i = 0; i < 100; i++) {
            Member member = new Member((long) i,
                    "user" + i,
                    RoleFactory.getInstance().getRole("user"));
            System.out.println(member);
        }
    }
}

这样我们通过提前创建 role 对象,使得频繁创建 member 对象时复用 role 对象,减少了 role 对象的频繁创建与销毁,大大节约了内存占用。

5、适用场景

相同对象或者相似对象需要频繁创建时,适合使用享元模式。

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

单例模式的目的是为了确保一个类只存在一个对象,需要自行实例化并提供全局访问方法。

享元模式的目的是为了对对象内蕴部分的复用,无需保证一个类只存在一个对象。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK