设计模式---享元模式

享元模式

享元模式,主要在于共享通用对象,减少内存的使用,从而提升系统的访问效率。而这部分共享对象通常比较耗费内存或者需要查询大量接口或者使用数据库资源,因此统⼀抽离作为共享对象使用。

享元模式可以分为在服务端和客户端,⼀般互联网H5和Web场景下大部分数据都需要服务端进行处理,比如数据库连接池的使用、多线程线程池的使用,除了这些功能外,还有些需要服务端进行包装后的处理下发给客户端,因为服务端需要做享元处理。在⼀些游戏场景下,很多都是客户端需要进行渲染地图效果,通过设置不同元素描述使用享元公用对象,减少内存的占用,让客户端的游戏更加流畅。

在享元模型的实现中需要使用到享元工厂来进行管理这部分独立的对象和共享的对象,避免出现线程安全的问题。

商品查询实现享元模式

网上购物时,在高并发秒杀的情况下,目前大多数使用Redis的分布式锁来控制确保库存数量的准确。但是在对商品信息进行查询时候不需要每次从库里面查询,因为这些信息是不变的,一般都会缓存到内存中。

这里模拟商品的查询,因为商品是不变的部分,而库存是变化的信息。

创建库存类

public class Stock {
 private int total; // 库存总数
 private int used; // 库存已⽤
 
 // get set ……方法
}

创建活动类 保存不变的活动信息

public class Activity {
 private Long id; // 活动ID
 private String name; // 活动名称
 private String desc; // 活动描述
 private Date startTime; // 开始时间
 private Date stopTime; // 结束时间
 private Stock stock; // 活动库存
 
 // get set ……方法
}

创建享元工厂,存在对象后直接使用,没有的话进行创建

public class ActivityFactory {
 static Map<Long, Activity> activityMap = new HashMap<Long, Activity>
();
 	public static Activity getActivity(Long id) {
 		Activity activity = activityMap.get(id);
 		if (activity == null) {
 		// 模拟从实际业务应⽤从接⼝中获取活动信息
		 activity = new Activity();
		 activity.setId(10001L);
		 activity.setName("当当双十一");
		 activity.setDesc("满一百减五十");
		 activity.setStartTime(new Date());
		 activity.setStopTime(new Date());
		 activityMap.put(id, activity);
   		}
 		return activity; 
  	}
 }

Redis工具类,原子类来模拟商品库存的消耗

public class RedisUtils {
 	private ScheduledExecutorService scheduledExecutorService =
Executors.newScheduledThreadPool(1);
 	private AtomicInteger stock = new AtomicInteger(0);
	 public RedisUtils() {
	 scheduledExecutorService.scheduleAtFixedRate(() -> {
	 // 模拟库存消耗
	 stock.addAndGet(1);
	 }, 0, 100000, TimeUnit.MICROSECONDS);
	 }
	 public int getStockUsed() {
	 return stock.get();
 	}
}

控制类,统一获取商品信息进行返回

public class ActivityHandler {
    private RedisUtils redisUtils = new RedisUtils();
 	public Activity queryActivityInfo(Long id) {
 	Activity activity = ActivityFactory.getActivity(id);
	// 模拟从Redis中获取库存变化信息
	 Stock stock = new Stock(1000, redisUtils.getStockUsed());
	 activity.setStock(stock);
	 return activity;
  }
}

总结:在⼀些有大量重复对象可复用的场景下,使用享元模式在服务端减少接口的调用,在客户端减少内存的占用,是这个设计模式的主要应用方式。

此外另外通过 map 结构的使用方式也可以看到,使用一个固定id来存放和获取对象,是非常关键的点。

但是它也有一些缺点,就是在一些复杂的业务中,不容易区分出内部和外部状态,就像我们活动信息部分与库存变化部分。如果不能很好的拆分,会将享元工厂设计的很混乱,难以维护。同时划分外部状态和内部状态时可能会引起线程安全问题,这一点需要注意。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值