注意:阅读本文时,强烈建议先阅读下 OneMall 项目的概要设计
1. 需求
由于我们需要对接各大商城的 API,所以我们需要在 Supplier 模块实现各大商城的 API client,提供一个 client 供其他模块来调用。每个商城的 API client 只需要一个就可以了。这个 client 就可以使用单例模式。
2. 实现
代码实现:
public class JdApiSingleton {
private static final JdApiSingleton self = new JdApiSingleton();
private JdApiSingleton() {
}
public static JdApiSingleton getJdApi() {
return self;
}
/**
* 获取商品信息
*
* @param url 地址
* @param param 参数
* @return 商品实体
*/
public static GoodsDTO getGoodsInfo(String url, Map<String, Object> param) {
String result = HttpClientUtil.get(url, param);
return JSONObject.parseObject(result, GoodsDTO.class);
}
/**
* 提交订单
*
* @param url 地址
* @param param 参数
* @return 订单信息
*/
public static OrderDTO submitOrder(String url, Map<String, Object> param) {
String result = HttpClientUtil.post(url, param);
return JSONObject.parseObject(result, OrderDTO.class);
}
单例模式比较简单,这里使用了”饿汉式”的设计,私有化构造方法,确保应用中只有一个实例,然后还有提供了其他各种 API,用于实现业务逻辑。
3. 类图
单例模式的类图比较简单,只需要一个 Singleton 就可以实现单例模式。单例模式不仅仅只有一种实现方式,上面这种“饿汉式”式最简单的实现。有兴趣的可以说搜一下其他的实现方式,由于本文讨论的是设计模式,这里不再详细讨论别的实现方式。
4. 扩展
在内存中产生一个实例很简单,但是,在有些情况下我们可能需要固定数量的实例,用来提高应用的性能。比如在多线程的情况下,我们可能需要为每个线程分配一个实例。这个时候我们就可以在内存中生成固定数量的实例,数量与线程池的大小保持一致。
代码实现:
public class JdApiSingletonPool {
//实例最大个数
private static final int MAX_NUM = 4;
private static final List<JdApiSingletonPool> pool = new ArrayList<>(MAX_NUM);
private JdApiSingletonPool() {
}
//初始化单例池
static {
for (int i = 0; i < MAX_NUM; i++) {
pool.add(new JdApiSingletonPool());
}
}
/**
* 获取实例
*
* @param index 下标
* @return 如果下标越界返回 null
*/
public static JdApiSingletonPool getJdApiSingleton(int index) {
if (index < 0 || index >= MAX_NUM) {
return null;
}
return pool.get(index);
}
// other api ...
我们通过初始化一个单例的集合来存储所有的单例。这样就能够保证内存中有固定数量的单例实例。
5. 总结
单例模式(Singleton Pattern): 确保某一个类只有一个实例,而且自行实例化并向整个系统提供这个实例。
这个定义有 3 个含义:
- 只能有一个实例(私有化构造方法)
- 自行实例化(自动初始化)
- 向整个系统提供这个实例(提供 get 方法获取自动初始化的实例)
单例模式的优点:
- 只有一个实例,节省了内存开销。减少了对象的创建和销毁的时间。
- 避免了对资源的多重占用。由于只有一个实例,在程序运行期间,只能有一个进程来操作这个实例。
- 全局访问。单例模式要求向整个系统提供这个实例,所以可以用来共享某些资源。
单例模式的缺点:
- 没有接口,不易扩展。如果需要新增一些 API 就需要对单例模式进行修改
- 与单一职责原则冲突。一个单例实例一般不会只实现一种业务逻辑。
6. 使用实例
- Spring 容器中的 Java Bean 就是采用的单例模式。每个 Bean 都是单例的。
- Java 中的 JDBC 连接对象 也是采用的单例模式。每个 JDBC 连接 都是单例的。
转载请注明出处
本文链接:zdran.com/20190818.ht…