接口是单例和工厂模式发挥解耦价值的基础:单例通过接口提供统一访问入口,工厂通过接口实现按需切换,二者结合使系统松耦合、易测试、可扩展。

接口编程本身不直接“实现”单例或工厂模式,但它是让这两种模式真正发挥解耦、可维护、可扩展价值的关键基础。单例负责控制实例数量,工厂负责封装创建逻辑,而接口则把“做什么”和“怎么做”彻底分开——这才是优雅的核心。
为什么必须先有接口,再谈单例和工厂
没有接口的单例只是“全局唯一对象”,容易变成硬编码、难以替换、无法Mock测试;没有接口的工厂只是“一堆 new”,一旦数据库从 MySQL 换成 PostgreSQL,所有调用处都得改。接口定义契约,让上层代码只依赖抽象,不关心具体实现。
- DAO 层定义 UserDAO 接口,而非直接写 UserMySqlDAO 类
- 业务类(如 UserService)持有 UserDAO 类型的字段,而非具体实现类
- 单例对象(如 UserManager)返回的也是接口类型实例,不是具体类
- 工厂(如 DAOFactory)生产的也是接口实例,由配置或环境决定返回哪个实现
单例 + 接口:提供稳定、统一的访问入口
单例不是为了“只有一个”,而是为了“只有一个可信入口”。结合接口后,它不再暴露实现细节,只暴露能力契约。
- 单例类(如 ConfigManager)内部持有一个 ConfigReader 接口引用
- 构造时通过工厂或配置注入具体实现(如 JsonConfigReader 或 DbConfigReader)
- 对外只暴露 getConfig(String key) 这样的接口方法,调用方完全不知底层是文件还是数据库
- 多线程安全可由双重检查锁(Java)、静态局部变量(C++)或 sync.Once(Go)保障,但接口层无需感知
工厂 + 接口:按需切换实现,零侵入扩展
工厂模式的价值,在于你增加一个新实现(比如新增 RedisCacheImpl),只需注册进工厂,其他代码一行不动。
- 定义 Cache 接口,含 put/get/clear 方法
- 编写 MemoryCache、RedisCache、MemcachedCache 等实现类
- 工厂类(如 CacheFactory)根据配置字符串("redis" / "memory")返回对应接口实例
- 业务模块通过 Cache cache = CacheFactory.getCache() 获取,后续所有操作都面向接口
Spring 和 Go 中的自然落地
现代框架早已将这套组合封装得极为简洁:Spring 默认 Bean 是单例,且天然基于接口注入;Go 的依赖注入库(如 wire)鼓励先定义 interface,再绑定 concrete struct。它们不强制你写 getInstance() 或 new Factory(),但背后仍是同一套思想——接口是协议,单例是生命周期策略,工厂是创建策略,三者协同才让系统松而不散。











