第一次接触设计模式是在十年前维护一个老旧的Java项目时。当时面对满屏重复的new操作和混乱的对象创建逻辑,我意识到需要一种更优雅的解决方案。设计模式就像是编程世界里的棋谱,记录了前人应对特定场景的最佳落子方式。单例和工厂模式作为创建型模式的代表,几乎出现在我参与过的每个中型以上项目中。
这两种模式都围绕着对象创建这个基础命题展开,但解决的是不同维度的痛点。单例确保全局唯一性,就像公司里的CEO职位;工厂模式封装创建细节,好比人力资源部门负责招聘的全流程。理解它们的差异点比记住定义更重要——单例控制实例数量,工厂控制实例化方式。
最早的饿汉式单例简单直接:
java复制public class CEO {
private static final CEO instance = new CEO();
private CEO() {}
public static CEO getInstance() {
return instance;
}
}
这种在类加载时就初始化的方式,就像公司注册时就确定CEO人选,虽然线程安全但可能造成资源浪费。后来我们更常用双重检查锁定的懒汉式:
java复制public class CFO {
private static volatile CFO instance;
private CFO() {}
public static CFO getInstance() {
if (instance == null) {
synchronized (CFO.class) {
if (instance == null) {
instance = new CFO();
}
}
}
return instance;
}
}
volatile关键字在这里就像公证处的印章,确保多线程环境下也能安全地完成单例初始化。我在金融系统开发中,这种写法成功解决了交易引擎实例的并发创建问题。
Joshua Bloch在《Effective Java》中提出的枚举单例,是我现在最推荐的写法:
java复制public enum CTO {
INSTANCE;
public void manageTeam() {
// 技术管理方法
}
}
这种写法不仅能防止反射攻击,还能自动处理序列化问题。去年在微服务架构改造时,我们用枚举单例重构了所有的配置管理器,代码量减少了30%的同时彻底解决了线程安全问题。
java复制Field instance = Singleton.class.getDeclaredField("instance");
instance.setAccessible(true);
instance.set(null, null);
内存泄漏:Android开发中单例持有Activity引用会导致内存泄漏。推荐使用WeakReference或依赖注入框架管理生命周期。
分布式陷阱:在Kubernetes集群中,每个Pod都会有自己的单例实例。这时需要改用分布式缓存或数据库实现真正的全局唯一。
在电商促销系统里,我们这样实现折扣工厂:
java复制public class DiscountFactory {
public static Discount create(String type) {
switch(type) {
case "FULL100": return new Full100Discount();
case "PERCENT": return new PercentDiscount();
default: throw new IllegalArgumentException();
}
}
}
虽然违背开闭原则,但对于促销策略这种低频变更的需求,简单工厂反而最实用。关键是要写好单元测试覆盖所有分支,我在团队中强制要求这类工厂的测试覆盖率必须达到100%。
开发跨平台UI框架时,我们采用这样的结构:
java复制interface ButtonFactory {
Button createButton();
}
class WindowsButtonFactory implements ButtonFactory {
public Button createButton() {
return new WindowsButton();
}
}
class MacButtonFactory implements ButtonFactory {
public Button createButton() {
return new MacButton();
}
}
这种模式就像特许经营模式,每个平台(Windows/Mac)都有自己的"加盟工厂"。在最近Flutter项目里,我们用它来管理不同平台的本地视图组件。
构建IoT设备控制套件时,抽象工厂派上大用场:
java复制interface DeviceKitFactory {
Sensor createSensor();
Controller createController();
Display createDisplay();
}
class HomeKitFactory implements DeviceKitFactory {
// 实现苹果HomeKit生态的系列产品
}
class AlexaFactory implements DeviceKitFactory {
// 实现亚马逊Alexa生态的系列产品
}
这就像为不同智能家居生态系统提供完整解决方案包。特别注意产品族内的兼容性问题,我们通过工厂接口的Javadoc明确约束各产品的协作方式。
结合单例和工厂模式的经典案例:
java复制public class ConnectionPool {
private static final ConnectionPool instance = new ConnectionPool();
private Map<String, Connection> pools = new ConcurrentHashMap<>();
private ConnectionPool() {
// 初始化默认连接池
}
public static ConnectionPool getInstance() {
return instance;
}
public Connection getConnection(String dbType) {
return pools.computeIfAbsent(dbType, type -> {
switch(type) {
case "MySQL": return new MySqlConnection();
case "Oracle": return new OracleConnection();
default: throw new IllegalArgumentException();
}
});
}
}
这种设计在SAAS系统中特别有用,既保证了连接池全局唯一,又通过工厂方法支持多数据库类型。我们在内存优化时,将computeIfAbsent改为异步加载模式,系统启动时间缩短了40%。
另一个典型案例是日志框架设计:
java复制public abstract class LoggerFactory {
private static LoggerFactory instance;
public static synchronized void setInstance(LoggerFactory factory) {
instance = factory;
}
public static Logger getLogger(String name) {
if(instance == null) {
synchronized(LoggerFactory.class) {
if(instance == null) {
String os = System.getProperty("os.name");
instance = os.contains("Windows") ?
new WindowsLoggerFactory() : new UnixLoggerFactory();
}
}
}
return instance.createLogger(name);
}
protected abstract Logger createLogger(String name);
}
这种设计巧妙之处在于:
在百万次调用的基准测试中:
| 实现方式 | 耗时(ns/op) | 内存占用 |
|---|---|---|
| 饿汉式 | 2.3 | 最低 |
| 双重检查锁 | 3.1 | 中等 |
| 静态内部类 | 2.8 | 低 |
| 枚举 | 2.5 | 低 |
实际项目中,我建议:对加载性能敏感用饿汉式,需要懒加载用静态内部类,考虑安全性用枚举。
java复制private Map<String, Product> cache = new WeakHashMap<>();
public Product create(String type) {
return cache.computeIfAbsent(type, t -> {
// 复杂的创建过程
return heavyInitialization(t);
});
}
java复制List<CompletableFuture> futures = Arrays.asList(
CompletableFuture.runAsync(() -> factory.create("A")),
CompletableFuture.runAsync(() -> factory.create("B"))
);
CompletableFuture.allOf(futures.toArray(new CompletableFuture[0])).join();
Spring等框架通过@Bean和@Component注解,实际上把单例和工厂的控制权转移到了容器。但理解底层模式仍然重要,比如:
java复制@Configuration
class AppConfig {
@Bean
@Scope("singleton")
public DataSource dataSource() {
// 本质上仍是单例模式
}
}
在Kotlin中,单例可以简化为:
kotlin复制object NetworkManager {
fun connect() { ... }
}
工厂模式可以用高阶函数实现:
kotlin复制fun createParser(type: String): () -> Parser = when(type) {
"JSON" -> ::JsonParser
"XML" -> ::XmlParser
else -> throw IllegalArgumentException()
}
在微服务架构中,我们这样组合使用:
这种组合在保证性能的同时,提供了极好的扩展性。去年双十一大促期间,这套架构平稳处理了每秒12万次的订单请求。