MST

星途 面试题库

面试题:Java中常见的反模式之单例模式的滥用及解决方案

在Java开发中,单例模式有时会被滥用,例如在多线程环境下出现问题或者不必要地使用单例导致资源浪费等情况。请阐述一种单例模式滥用的场景,并给出对应的解决方案,同时用代码示例说明。
22.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试

滥用场景

在某些场景下,系统中有多个模块可能会独立运行且互不干扰,每个模块都有自己的业务逻辑和数据状态,这种情况下如果为每个模块都使用单例模式,就可能造成资源浪费。比如,在一个电商系统中,订单模块和商品模块是相对独立的,若都使用单例模式,即使两个模块之间没有交互,单例对象也会一直占用内存资源,而实际上这两个模块可以独立实例化以节省资源。

解决方案

根据业务需求,合理判断是否真的需要单例。如果不需要单例模式的强一致性和全局唯一性,可以采用普通的实例化方式创建对象。若某些模块确实需要共享数据,可以考虑使用其他设计模式如享元模式,它与单例模式不同,享元模式注重对象的复用,通过共享对象来减少内存开销,而单例模式强调全局唯一实例。

代码示例

  1. 滥用单例模式的代码示例
public class Singleton {
    private static Singleton instance;
    private Singleton() {}
    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

// 模拟不同模块使用单例
class OrderModule {
    private Singleton singleton;
    public OrderModule() {
        singleton = Singleton.getInstance();
    }
}

class ProductModule {
    private Singleton singleton;
    public ProductModule() {
        singleton = Singleton.getInstance();
    }
}
  1. 采用普通实例化方式的改进示例
public class NormalObject {
    public NormalObject() {}
}

class OrderModuleNew {
    private NormalObject normalObject;
    public OrderModuleNew() {
        normalObject = new NormalObject();
    }
}

class ProductModuleNew {
    private NormalObject normalObject;
    public ProductModuleNew() {
        normalObject = new NormalObject();
    }
}
  1. 享元模式示例(简单示意)
import java.util.HashMap;
import java.util.Map;

// 享元对象接口
interface Flyweight {
    void operation();
}

// 具体享元对象
class ConcreteFlyweight implements Flyweight {
    private String intrinsicState;
    public ConcreteFlyweight(String state) {
        this.intrinsicState = state;
    }
    @Override
    public void operation() {
        System.out.println("ConcreteFlyweight operation with intrinsic state: " + intrinsicState);
    }
}

// 享元工厂
class FlyweightFactory {
    private static Map<String, Flyweight> flyweights = new HashMap<>();
    public static Flyweight getFlyweight(String key) {
        if (!flyweights.containsKey(key)) {
            flyweights.put(key, new ConcreteFlyweight(key));
        }
        return flyweights.get(key);
    }
}

// 使用享元模式
class ModuleUsingFlyweight {
    private Flyweight flyweight;
    public ModuleUsingFlyweight(String key) {
        flyweight = FlyweightFactory.getFlyweight(key);
    }
    public void doSomething() {
        flyweight.operation();
    }
}