JAVA【设计模式】享元模式
一、定义
外观模式:主要适用于减少对象的创建,以减少内存的使用和提高性能,例如缓存设计之类的,它提供了减少对象创建数量从而改善应用所需对象结构方式。
二、示例:
模拟场景:
1、商品下单的项⽬从最初的⽇均⼗⼏单到⼀个⽉后每个时段秒杀量破⼗万的项⽬。⼀般在最初如果没有经验的情况下可能会使⽤数据库⾏级锁的⽅式下保证商品库存的扣减操作,但是随着业务的快速发展秒杀的⽤户越来越多,这个时候数据库已经扛不住了,⼀般都会使⽤redis的分布式锁来控制商品库存。
传统编码方式
每次都去数据库里面查询数据,一旦访问量增加服务器承受不了这么大的压力
package com.qf.design.structure.flyweight.tradition;
import com.qf.design.structure.flyweight.entity.Activity;
import com.qf.design.structure.flyweight.entity.Stock;
import java.util.Date;
public class ActivityController {
public Activity queryActivityInfo(Long id) {
// 模拟从实际业务应用从接口中获取活动信息
// 业务的数据来自于数据库,每次都需要访问数据库
Activity activity = new Activity();
activity.setId(10001L);
activity.setName("图书嗨乐");
activity.setDesc("图书优惠券分享激励分享活动第二期");
activity.setStartTime(new Date());
activity.setStopTime(new Date());
activity.setStock(new Stock(1000,1));
return activity;
}
}
享元模式设计
加入redis缓存设计,在redis中查询和修改库存
package com.qf.design.structure.flyweight.design.utils;
import org.omg.CORBA.PUBLIC_MEMBER;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
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();
}
}
减少对象的创建
package com.qf.design.structure.flyweight.design;
import com.qf.design.structure.flyweight.entity.Activity;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class ActivityFatory {
static Map<Long, Activity> activityMap=new HashMap<>();
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;
}
}
package com.qf.design.structure.flyweight.design;
import com.qf.design.structure.flyweight.design.utils.RedisUtils;
import com.qf.design.structure.flyweight.entity.Activity;
import com.qf.design.structure.flyweight.entity.Stock;
public class ActivityController {
private RedisUtils redisUtils=new RedisUtils();
public Activity queryActivityInfo(Long id) {
Activity activity = ActivityFatory.getActivity(id);
Stock stock = new Stock(1000, redisUtils.getStockUsed());
activity.setStock(stock);
return activity;
}
}
测试:ApiTest
package com.qf.design.structure.flyweight.design;
import com.alibaba.fastjson.JSON;
import com.qf.design.structure.flyweight.entity.Activity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ApiTest {
private static Logger logger= LoggerFactory.getLogger(ApiTest.class);
public static void main(String[] args) throws InterruptedException {
ActivityController activityController=new ActivityController();
for (int i = 0; i < 10; i++) {
Activity activity = activityController.queryActivityInfo(10000L);
logger.info(JSON.toJSONString(activity));
Thread.sleep(1200);
}
}
}
总结:
关于享元模式的设计可以着重学习享元⼯⼚的设计,在⼀些有⼤量重复对象可复⽤的场景下,使⽤此场景在服务端减少接⼝的调⽤,在客户端减少内存的占⽤。是这个设计模式的主要应⽤⽅式。
另外通过 map 结构的使⽤⽅式也可以看到,使⽤⼀个固定id来存放和获取对象,是⾮常关键的点。⽽且不只是在享元模式中使⽤,⼀些其他⼯⼚模式、适配器模式、组合模式中都可以通过map结构存放服务供外部获取,减少ifelse的判断使⽤。