設計模式之工廠模式案例(支付)

我們如何能根據一個業務來優雅的實現高擴展性,可維護性高的代碼呢,下面介紹一種我們常用的設計模式--工廠模式

具體代碼實現:

sql腳本:

create table channel
(
  channel_id   int auto_increment
    primary key,
  channel_name varchar(40) null
  comment '渠道名稱',
  simple_name  varchar(20) null
  comment '渠道簡稱',
  dis_count    int         null
  comment '渠道折扣',
  status       varchar(20) null
  comment '渠道開啓狀態'
)
  comment '支付渠道表';


INSERT INTO `channel`(`channel_id`, `channel_name`, `simple_name`, `dis_count`, `status`) VALUES (1, '中國農業銀行', 'ABC', '1', 'open');
INSERT INTO `channel`(`channel_id`, `channel_name`, `simple_name`, `dis_count`, `status`) VALUES (2, '中國工商銀行', 'ICBC', '0.91', 'open');
INSERT INTO `channel`(`channel_id`, `channel_name`, `simple_name`, `dis_count`, `status`) VALUES (3, '中國郵政儲蓄銀行', 'PSBC', '0.5', 'open');


create table goods
(
  goods_id   int auto_increment
  comment 'id'
    primary key,
  goods_name varchar(50)  null
  comment '商品名稱',
  abstracts  varchar(500) null
  comment '商品簡介',
  status     varchar(50)  null
  comment '商品狀態',
  price      int          null
  comment '商品價格'
)
  comment '商品表';
INSERT INTO `goods`(`goods_id`, `goods_name`, `abstracts`, `status`, `price`) VALUES (1, '深入理解JVM', 'Java高級', '已上架', 55);

java代碼:

package tjs.bf.beans.pay;

import lombok.Data;
import lombok.ToString;
import tjs.bf.beans.BaseBean;

import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc:
 */
@Data
@ToString
public class Goods extends BaseBean {
    private Integer goodsId;

    private String goodsName;

    private BigDecimal price;

    private String abstracts;

    private String status;
}
package tjs.bf.beans.pay;

import lombok.Data;
import lombok.ToString;
import tjs.bf.beans.BaseBean;

import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc:
 */
@Data
@ToString
public class Channel extends BaseBean {

    private Integer ChannelId;

    private String ChannelName;

    private String simpleName;

    private BigDecimal disCount;

    private String status;
}
package tjs.bf.api.impl.pay;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc:
 */
@Target(ElementType.TYPE)//類註解
@Retention(RetentionPolicy.RUNTIME)//在JAM中可以取到
public @interface Pay {
    int channelId();
}
package tjs.bf.api.impl.pay;

import org.springframework.beans.factory.annotation.Autowired;
import tjs.bf.beans.pay.Channel;
import tjs.bf.beans.pay.Goods;
import tjs.bf.config.ApplicationContextHelper;
import tjs.bf.mapper.pay.ChannelMapper;
import tjs.bf.mapper.pay.GoodsMapper;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc: 中國農業銀行
 */
@Pay(channelId = 1)
public class ABCbank extends ApplicationContextHelper implements Strategy {

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private ChannelMapper channelMapper;
    @Override
    public BigDecimal calPrice(int channelId, int goodsId) {
        Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
        Channel channel = channelMapper.selectByPrimaryKey(channelId);
        return channel.getDisCount().multiply(goods.getPrice());
    }
}
package tjs.bf.api.impl.pay;

import com.alibaba.dubbo.config.annotation.Service;
import org.springframework.beans.factory.annotation.Autowired;
import tjs.bf.beans.pay.Channel;
import tjs.bf.beans.pay.Goods;
import tjs.bf.config.ApplicationContextHelper;
import tjs.bf.mapper.pay.ChannelMapper;
import tjs.bf.mapper.pay.GoodsMapper;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc: 中國工商銀行
 */
@Pay(channelId = 2)
public class ICBCBank extends ApplicationContextHelper implements Strategy {

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private ChannelMapper channelMapper;
    @Override
    public BigDecimal calPrice(int channelId, int goodsId) {
        Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
        Channel channel = channelMapper.selectByPrimaryKey(channelId);
        return channel.getDisCount().multiply(goods.getPrice());
    }
}
package tjs.bf.api.impl.pay;

import org.springframework.beans.factory.annotation.Autowired;
import tjs.bf.beans.pay.Channel;
import tjs.bf.beans.pay.Goods;
import tjs.bf.config.ApplicationContextHelper;
import tjs.bf.mapper.pay.ChannelMapper;
import tjs.bf.mapper.pay.GoodsMapper;

import javax.annotation.Resource;
import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc: 中國郵政儲蓄銀行
 */
@Pay(channelId = 3)
public class PSBCbank extends ApplicationContextHelper implements Strategy {

    @Resource
    private GoodsMapper goodsMapper;

    @Resource
    private ChannelMapper channelMapper;
    @Override
    public BigDecimal calPrice(int channelId, int goodsId) {
        Goods goods = goodsMapper.selectByPrimaryKey(goodsId);
        Channel channel = channelMapper.selectByPrimaryKey(channelId);
        return channel.getDisCount().multiply(goods.getPrice());
    }
}
package tjs.bf.api.impl.pay;

import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc:
 */
public interface Strategy {

    //計算採用不同渠道商品的優惠價格
    BigDecimal calPrice(int channelId, int goodsId);
}
package tjs.bf.api.impl.pay;

import org.reflections.Reflections;

import java.util.HashMap;
import java.util.Set;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc: 工廠類
 */
public class StrategyFactory {

    private static StrategyFactory factory = new StrategyFactory();

    private static HashMap<Integer,String> source_map = new HashMap<>();

    private StrategyFactory(){}

    /** 
    * @desc: 根據我們渠道ID創建所需要的實現類 
    * @author: SJT
    * @date: 2019/3/18        
    * @param: [channelId] 
    * @return: tjs.bf.api.impl.pay.Strategy 
    */ 
    public Strategy create(int channelId) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        String clazz = source_map.get(channelId);
        Class<?> clazz_ = Class.forName(clazz);
        return (Strategy) clazz_.newInstance();
    }

    /** 
    * @desc: 利用反射來獲取自定義類註解中渠道ID,將我們渠道ID與相對應的實現類相關聯放進我們維護的Map裏 
    * @author: SJT
    * @date: 2019/3/18        
    * @param:  
    * @return:  
    */ 
    static {
        Reflections reflections = new Reflections("tjs.bf.api.impl.pay");
        Set<Class<?>> classSet = reflections.getTypesAnnotatedWith(Pay.class);
        classSet.stream().forEach(clazz ->{
            Pay pay = clazz.getAnnotation(Pay.class);
            source_map.put(pay.channelId(),clazz.getCanonicalName());
        });
    }

    /** 
    * @desc: 獲取工廠實例 
    * @author: SJT
    * @date: 2019/3/18        
    * @param: [] 
    * @return: tjs.bf.api.impl.pay.StrategyFactory 
    */ 
    public static StrategyFactory getInstance(){
        return factory;
    }
}
package tjs.bf.api.impl.pay;

import com.alibaba.dubbo.config.annotation.Service;
import tjs.bf.api.PayService;

import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc: 支付接口實現類
 */
@Service
public class PayServiceImpl implements PayService {

    @Override
    public BigDecimal calPrice(int channelId, int goodsId) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        Strategy strategy = StrategyFactory.getInstance().create(channelId);
        return strategy.calPrice(channelId,goodsId);
    }
}
package tjs.bf.api;

import java.math.BigDecimal;

/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc:
 */
public interface PayService {

    public BigDecimal calPrice(int channelId,int goodsId) throws IllegalAccessException, InstantiationException, ClassNotFoundException;
}
package tjs.bf.controller.pay;

import com.alibaba.dubbo.config.annotation.Reference;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tjs.bf.api.PayService;
import tjs.bf.common.JsonData;


/**
 * @project: springboot-dubbo-parent
 * @author: SJT
 * @date: 2019/3/17
 * @desc:
 */
@RestController
@RequestMapping("/pay")
public class PayController {

    @Reference
    PayService payService;

    @GetMapping("/pay")
    public JsonData pay(Integer channelId,Integer goodsId) throws IllegalAccessException, ClassNotFoundException, InstantiationException {
        return JsonData.success(payService.calPrice(channelId,goodsId));
    }
}

ok到此結束,有興趣的可以試試~.~

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章