设计模式——多例模式(23种之外)

发布于:2024-07-15 ⋅ 阅读:(149) ⋅ 点赞:(0)

多例模式(Multiton Pattern)是一种特殊的设计模式,它属于创建型模式。与单例模式(Singleton Pattern)相比,多例模式允许一个类有多个实例,但是实例的数量是有限制的,并且这些实例在全局范围内是共享的。这种模式适用于当系统中有且仅有几个对象实例被频繁使用,且这些对象的创建和销毁开销较大时。

在我的SpringBoot项目中遇到的一个问题,最后使用多例模式解决了。问题是我需要通过传入参数实例化一个对象,希望如果出入的参数相同那么得到的实例应该是一样的,如果参数不同则实例化的参数是不同的。这个问题我一开始想到了单例模式和工厂模式结合来解决,在工厂中判断参数是否已经存在从而创建单例实例,后面越想越觉得自己搞复杂了,虽然可以解决这个问题,最后果然发现还有一种多例模式可以完美解决这个问题。那么,下面就开始演示如何使用多例模式:

需要实例化的User类

public class User {
    String id;

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

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                '}';
    }
}

直接获取对象的缺点

我们正常的实例化其实是不满足条件的,例如如下代码:

public class MainTest {
    public static void main(String[] args) { 
        User user1 = new User("123");
        User user2 = new User("123");
        
        System.out.println(user1.hashCode());
        System.out.println(user2.hashCode());

        System.out.println(user1 == user2);
    }
}

输出结果

128893786
1732398722
false

显然,这样new出来的两个对象不是同一个,但是在这种情况下,我们希望通过参数构造的对象只要参数相同就能拿到同一个对象,类似单例模式,而不同参数则创建新的对象。这种情况就非常适合多例模式,下面介绍多例模式解决这个问题。

多例模式

多例模式的特点

  • 实例数量有限:与单例模式不同,多例模式允许创建多个实例,但实例的数量是有限的。
  • 全局访问:所有实例都是全局可访问的,通常通过一个全局的访问点来获取实例。
  • 实例唯一性:在允许的范围内,每个实例都是唯一的。

下面是线程安全的实现,这里我们使用一个工厂类来管理我们的User,只要是相同的id就一定能够获得相同的User,不同的id拿到的User不同。代码如下:

public class UserMultitonFactory {
    private static final ConcurrentHashMap<String, User> userMap = new ConcurrentHashMap<>();

    private UserMultitonFactory(){} // 私有构造方法防止new实例化

    public static User getInstance(String id) {
        // 使用computeIfAbsent方法确保线程安全的实例创建
        return userMap.computeIfAbsent(id,k -> new User(k)); // 这个k就是id
    }

    public static void destroyInstance(String id){
        userMap.remove(id);
    }
}

测试

public class MainTest {
    public static void main(String[] args) {
        User user1 = UserMultitonFactory.getInstance("123");
        User user2 = UserMultitonFactory.getInstance("123");
        User user3 = UserMultitonFactory.getInstance("001");

        System.out.println(user1.hashCode());
        System.out.println(user2.hashCode());
        System.out.println(user3.hashCode());
    }
}

结果

1108411398
1108411398
1394438858

这里我们是使用一个工厂类来管理User的创建,当然也可以让User自己成为一个多例模式类,代码如下:


public class UserMultiton {
    String id;

    private static final ConcurrentHashMap<String, UserMultiton> userMap = new ConcurrentHashMap<>();

    private UserMultiton(String id) { // 禁止外部创建该类
        this.id = id;
    }

    public static UserMultiton getInstance(String id){
        // 使用computeIfAbsent方法确保线程安全的实例创建
        return userMap.computeIfAbsent(id,k -> new UserMultiton(k)); // 这个k就是id
    }

    public static void destroyInstance(String id){
        userMap.remove(id);
    }

    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    @Override
    public String toString() {
        return "User{" +
                "id='" + id + '\'' +
                '}';
    }
}

应用场景

多例模式是一种创建型设计模式,其应用场景主要在于管理可重复使用的资源,如线程池、数据库连接池等。这些场景中,多例模式能够复用已有实例,避免重复创建对象,从而提高系统性能并避免浪费系统资源。

缺点

多例模式的缺点包括:

  • 难以扩展:多例模式的实例数量是固定的,难以动态地增加或减少实例数量。
  • 难以测试:由于多例模式的实例数量是固定的,难以对每个实例进行单独的测试。
  • 破坏封装性:多例模式需要全局访问实例,这破坏了封装性,使得代码难以维护和扩展。
  • 代码复杂度高:多例模式的实现需要考虑线程安全、序列化等问题,因此代码复杂度较高。

网站公告

今日签到

点亮在社区的每一天
去签到