常用设计模式的实际使用
单例模式
饿汉式单例模式:
springboot启动会加载Bean到容器里,后续调用都用同一个实例,相关注解@Componet , @Bean , @Service等等,线程安全,因为类加载的时候已经实例化了,不用加锁,执行效率高,但会占用内存。
@Slf4j
@Component
public class SingleDemo {
public SingleDemo() {
log.info("初始化单例");
}
public String doSome(){
return "123";
}
}
懒汉式单例模式:
需要用到时才进行加载,什么时候用就什么时候new实例,因为线程不安全,所以需要加锁,效率比饿汉式差,但需要用时才加载,节省空间。
@Slf4j
@Component
@Lazy
public class SingleDemo {
public SingleDemo() {
log.info("初始化单例");
}
public String doSome(){
return "123";
}
}
策略模式+工厂模式:实现促销执行
/**
* 促销策略
* */
public interface PromStrategy {
void executeProm();
}
实现策略类,分别有满减优惠和折扣促销,后续每增加一种促销方式就新增一个策略类
@Slf4j
@Service("favour")
public class FavourStrategy implements PromStrategy{
@Override
public void executeProm() {
log.info("执行优惠促销");
}
}
@Slf4j
@Service("discount")
public class DiscountStrategy implements PromStrategy{
@Override
public void executeProm() {
log.info("执行折扣促销");
}
}
使用Spring工厂管理各个策略类
@Slf4j
@Component
public class PromService implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
PromService.applicationContext = applicationContext;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
public static PromStrategy getStrategy(String className){
PromStrategy promStrategy = null;
try {
promStrategy = (PromStrategy) applicationContext.getBean(className);
}catch (Exception e){
log.error("找不到Bean");
}
return promStrategy;
}
}
@Service
public class ExecutePromServiceImpl implements ExecutePromService{
@Override
public void executePromStrategy() {
PromStrategy strategy = PromService.getStrategy("favour");
//执行促销
strategy.executeProm();
}
}
责任链模式
public interface Process{
void executeProcess();
}
public abstract class AbstractProcess implements Process {
@Override
public void executeProcess() {}
}
@Slf4j
public class ApprovalProcess extends AbstractProcess{
@Override
public void executeProcess() {
log.info("执行审批流程!");
}
}
@Slf4j
public class SubmitProcess extends AbstractProcess{
@Override
public void executeProcess() {
log.info("执行提交流程!");
}
}
public class DefaultProcessChain implements ProcessChain{
private List<Process> processList;
public DefaultProcessChain() {
this.processList = new ArrayList<>();
}
@Override
public ProcessChain add(Process process) {
processList.add(process);
return this;
}
@Override
public void executeProcess() {
for(Process process:processList){
process.executeProcess();
}
}
}
public class DefaultProcessChainBuilder {
private static ProcessChain chain;
private DefaultProcessChainBuilder(){
throw new AssertionError();
}
public synchronized static ProcessChain build(){
if(!ObjectUtils.isEmpty(chain)){
return chain;
}
chain = new DefaultProcessChain();
chain.add(new SubmitProcess());
chain.add(new ApprovalProcess());
return chain;
}
}
@Service
public class ProcessServiceImpl implements ProcessService{
@Override
public void executeProcess() {
DefaultProcessChainBuilder.build().executeProcess();
}
}
适配器模式:实现旧接口的二次封装
- 场景:目前手上有一套1.0的老代码
- 需要在这个老代码的基础上构建新代码,但要提供接口给别人面向新接口开发
- 所以需要适配器模式,别人实现的是v2.0,内部是v1.0,调用也是v2.0
- 实际应用场景:例如基于第三方类库,Redis ES提供的API,我们可以通过
- 适配器模式去把Redis的API适配到我们开发的接口,进行二次封装
- get、set、mset、mget,一套接口;适配器,DAORedisImpl就是一个适配器,
- 这个适配器实现的是我们的DAO接口,
- 在我们的save、update、remove等方法中,去调用redis客户端的get、set、mset、mget等方法。
- 这里的旧接口就相当于redis提供的API,我们可以注入在我们想适配的接口中
@Slf4j
@Service
public class StockServiceV2Impl extends StockServiceImpl implements StockService{
@Override
public void updateStock() throws Exception {
log.info("新逻辑执行");
//旧逻辑执行
super.updateStock();
}
}
@Slf4j
@Service
public class StockServiceImpl implements StockService {
@Autowired
private PayOrderStockCommandFactory payOrderStockCommandFactory;
@Override
public void updateStock() throws Exception {
log.info("更新库存");
StockUpdatper stockUpdatper = payOrderStockCommandFactory.create();
stockUpdatper.updateStock();
}
}
状态模式:实现订单状态流转
适合场景,数据有状态,状态就一定会流转,从状态1变成状态2
将不同的状态要执行的代码逻辑封装在不同的state类中
有一个context类,负责根据传入的参数,决定这份数据的状态流转到什么状态
同时负责执行那个新状态的代码逻辑
public interface State {
//变更状态操作
void changeState();
}
@Slf4j
public class NewState implements State{
@Override
public void changeState() {
log.info("订单新建状态");
}
}
@Slf4j
public class ApprovedState implements State{
@Override
public void changeState() {
log.info("订单更改为:待审批状态");
}
}
@Slf4j
public class FinishState implements State{
@Override
public void changeState() {
log.info("订单状态变更为:已完成状态");
}
}
public class StateContext {
private State status;
public StateContext(State state) {
this.status=state;
this.status.changeState();
}
public void executeChange(Integer type){
if(type==1){
this.status = new ApprovedState();
}else if(type==2){
this.status = new FinishState();
}
this.status.changeState();
}
public static void main(String[] args) {
StateContext stateContext = new StateContext(new NewState());
stateContext.executeChange(1);
}
}
模板方法模式:实现门店或营运区的限购逻辑
把通用运算逻辑和特殊运算逻辑拆分,特殊逻辑分别区分在门店和营运区的操作
public interface LimitBuyService {
//限购操作
void calculate();
}
@Slf4j
public abstract class AbstractLimitBuyTemplate implements LimitBuyService{
@Override
public void calculate() {
specificCalculate();
commonCalculate();
}
private void commonCalculate(){
log.info("执行通用逻辑");
}
protected abstract void specificCalculate();
}
@Slf4j
@Service
public class RegionLimitCalculate extends AbstractLimitBuyTemplate{
@Override
protected void specificCalculate() {
log.info("执行营运区限购运算逻辑");
}
}
@Slf4j
@Service
public class StoreLimitCalculate extends AbstractLimitBuyTemplate{
@Override
protected void specificCalculate() {
log.info("执行门店限购逻辑");
}
}
模板方法模式+工厂方法模式+命令模式:实现库存更新
例如更新库存这个操作,可以把更新库存的通用流程和方法封装成一个模版,把通用的部分在抽象模板写好,特殊计算部分,例如提交订单,退款入库,采购入库,每一个独立的命令可以继承该父类去执行独立的方法
@Slf4j
public abstract class AbstractStockUpdatper implements StockUpdatper{
private StockMapper stockMapper;
public AbstractStockUpdatper(StockMapper stockMapper) {
this.stockMapper=stockMapper;
}
@Override
public void updateStock(){
executeUpdateStock();
executeUpdateStockStatus();
setCommandType();
}
/**
* 特殊计算逻辑-设置更新的执行命令
* 区别于提交订单,退款入库,采购入库等等命令
* */
protected abstract void setCommandType() throws Exception;
/**
* 通用模板方法-更新状态
* */
private void executeUpdateStockStatus(){
log.info("执行通用模板方法-更新状态");
}
/**
* 实际执行更新库存操作
* */
private void executeUpdateStock(){
log.info("执行更新数据库库存操作");
stockMapper.executeUpdateStock();
}
}
使用命令模式,让命令继承模板方法,重写对应的特殊操作
@Slf4j
@Component
public class PayOrderStockCommand extends AbstractStockUpdatper{
public PayOrderStockCommand(StockMapper stockMapper) {
super(stockMapper);
}
/**
* 执行模板特殊方法
* */
@Override
protected void setCommandType() throws Exception {
log.info("完成更新库存,设置该库存更新操作为支付订单");
}
}
通过使用工厂模式构建对应的命令对象
public class PayOrderStockCommandFactory extends AbstractStockUpdatperFactory{
@Autowired
private StockMapper stockMapper;
@Override
public StockUpdatper create() {
log.info("构建命令");
return new PayOrderStockCommand(stockMapper);
}
}
执行命令操作
@Slf4j
@Service
public class StockServiceImpl implements StockService {
@Autowired
private PayOrderStockCommandFactory payOrderStockCommandFactory;
@Override
public void updateStock() throws Exception {
log.info("更新库存");
StockUpdatper stockUpdatper = payOrderStockCommandFactory.create();
stockUpdatper.updateStock();
}
}