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

07-14 1886阅读

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

设计模式——多例模式(23种之外)
(图片来源网络,侵删)

在我的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 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 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 + '\'' +
                    '}';
        }
    }
    

    应用场景

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

    缺点

    多例模式的缺点包括:

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

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]