为了让我们的案例更加贴近实际开发, 这里我们来模拟一下互联网电商中
促销拉新下的业务场景, 新用户注册立即参与抽奖活动 ,奖品的种类有: 打折券,
免费优酷会员,小礼品
(1)不考虑设计原则,不使用设计模式的方式进行开发,代码如下:
import java.util.Map;
/**
* 获奖信息实体类
**/
public class AwardInfo {
private String uid; //用户id
private Integer awardTypes; //奖品类型: 1 打折券 ,2 优酷会员 , 3 小礼品
private String awardNumber; //奖品编号
private Map<String,String> extMap; //额外信息
public AwardInfo() {
}
@Override
public String toString() {
return "AwardInfo{" +
"uid='" + uid + '\'' +
", awardTypes=" + awardTypes +
", awardNumber='" + awardNumber + '\'' +
", extMap=" + extMap +
'}';
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public Integer getAwardTypes() {
return awardTypes;
}
public void setAwardTypes(Integer awardTypes) {
this.awardTypes = awardTypes;
}
public String getAwardNumber() {
return awardNumber;
}
public void setAwardNumber(String awardNumber) {
this.awardNumber = awardNumber;
}
public Map<String, String> getExtMap() {
return extMap;
}
public void setExtMap(Map<String, String> extMap) {
this.extMap = extMap;
}
}
/**
* 打折券信息实体类
**/
public class DiscountInfo {
//属性信息省略......
}
/**
* 优酷会员实体类
**/
public class YouKuMember {
//属性信息省略
}
/**
* 小礼品实体类
**/
public class SmallGiftInfo {
private String userName;
private String userPhone;
private String orderId;
private String address;
@Override
public String toString() {
return "SmallGiftInfo{" +
"userName='" + userName + '\'' +
", userPhone='" + userPhone + '\'' +
", orderId='" + orderId + '\'' +
", address='" + address + '\'' +
'}';
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getUserPhone() {
return userPhone;
}
public void setUserPhone(String userPhone) {
this.userPhone = userPhone;
}
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
/**
* 打折券响应信息封装实体类
**/
public class DiscountResult {
private String status; //状态码
private String message; //信息
public DiscountResult(String status, String message) {
this.status = status;
this.message = message;
}
public String getStatus() {
return status;
}
public void setStatus(String status) {
this.status = status;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
/**
* 打折券服务
**/
public class DiscountService {
public DiscountResult sendDiscount(String uid, String awardNumber){
System.out.println("向用户发送一张打折券: " + uid + " , " + awardNumber);
return new DiscountResult("200","发放打折券成功!");
}
}
/**
* 小礼品服务
**/
public class SmallGiftService {
public Boolean giveSmallGift(SmallGiftInfo smallGiftInfo){
System.out.println("小礼品已发送,获奖用户注意查收! " + JSON.toJSON(smallGiftInfo));
return true;
}
}
/**
* 优酷会员
**/
public class YouKuMemberService {
public void openMember(String bindMobile, String awardNumber){
System.out.println("发放优酷会员: " + bindMobile + " , " + awardNumber);
}
}
/**
* 发放奖品接口
**/
public class DeliverController {
/**
* 按照类型的不同发放奖品
* 奖品类型: 1 打折券 ,2 优酷会员 , 3 小礼品, 4 优惠券
* @param awardInfo
*/
public void awardToUser(AwardInfo awardInfo){
if(awardInfo.getAwardTypes() == 1){ //打折券
DiscountService discountService = new DiscountService();
DiscountResult discountResult = discountService.sendDiscount(awardInfo.getUid(), awardInfo.getAwardNumber());
System.out.println("打折券发放成功!" + discountResult );
}else if(awardInfo.getAwardTypes() == 2){//优酷会员
String phone = awardInfo.getExtMap().get("phone");
YouKuMemberService youKuMemberService = new YouKuMemberService();
youKuMemberService.openMember(phone,awardInfo.getAwardNumber());
System.out.println("优酷会员发放成功!");
} else if(awardInfo.getAwardTypes() == 3){//小礼品
//封装收获人信息
SmallGiftInfo info = new SmallGiftInfo();
info.setUserPhone(awardInfo.getExtMap().get("phone"));
info.setUserName(awardInfo.getExtMap().get("username"));
info.setAddress(awardInfo.getExtMap().get("address"));
info.setOrderId(UUID.randomUUID().toString());
SmallGiftService smallGiftService = new SmallGiftService();
Boolean aBoolean = smallGiftService.giveSmallGift(info);
if(aBoolean){
System.out.println("小礼品发放成功!");
}
}
}
}
通过单元测试,来对上面的接口进行测试,验证代码质量
public class TestApi01 {
DeliverController deliverController = new DeliverController();
//测试发放奖品接口
@Test
public void test01(){
//1. 发放打折券优惠
AwardInfo info1 = new AwardInfo();
info1.setUid("1001");
info1.setAwardTypes(1);
info1.setAwardNumber("DEL12345");
deliverController.awardToUser(info1);
}
@Test
public void test02(){
//2. 发放优酷会员
AwardInfo info2 = new AwardInfo();
info2.setUid("1002");
info2.setAwardTypes(2);
info2.setAwardNumber("DW12345");
Map<String,String> map = new HashMap<>();
map.put("phone","13512341234");
info2.setExtMap(map);
deliverController.awardToUser(info2);
}
@Test
public void test03(){
//2. 发放小礼品
AwardInfo info3 = new AwardInfo();
info3.setUid("1003");
info3.setAwardTypes(3);
info3.setAwardNumber("SM12345");
Map<String,String> map2 = new HashMap<>();
map2.put("username","大远");
map2.put("phone","13512341234");
map2.put("address","北京天安门");
info3.setExtMap(map2);
deliverController.awardToUser(info3);
}
}
对于上面的实现方式,如果我们有想要添加的新的奖品时,势必要改动
DeliverController的代码,违反开闭原则.而且如果有的抽奖接口出现问题,那么对
其进行重构的成本会非常高.
除此之外代码中有一组if分支判断逻辑,现在看起来还可以,但是如果经历几次迭
代和拓展,后续ifelse肯定还会增加.到时候接手这段代码的研发将会十分痛苦.
简单工厂不是一种设计模式,反而比较像是一种编程习惯。简单工厂模式又叫做静态工厂方法模式(static Factory Method pattern),它是通过使用静态方法接收不同的参数来返回不同的实例对象。
public interface IFreeGoods {
ResponseResult sendFreeGoods(AwardInfo awardInfo);
}
/**
* 具体工厂: 生成免费商品
**/
public class FreeGoodsFactory {
public static IFreeGoods getInstance(Integer awardType){
IFreeGoods iFreeGoods = null;
if(awardType == 1){ //打折券
iFreeGoods = new DiscountFreeGoods();
}else if(awardType == 2){ //优酷会员
iFreeGoods = new YouKuMemberFreeGoods();
}else if(awardType == 3){ //小礼品
iFreeGoods = new SmallGiftFreeGoods();
}
return iFreeGoods;
}
}
/**
* 模拟打折券服务
**/
public class DiscountFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendFreeGoods(AwardInfo awardInfo) {
System.out.println("向用户发放一张打折券: " + awardInfo.getUid() + " , " + awardInfo.getAwardNumber());
return new ResponseResult("200","打折券发放成功!");
}
}
/**
* 小礼品发放服务
**/
public class SmallGiftFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendFreeGoods(AwardInfo awardInfo) {
SmallGiftInfo smallGiftInfo = new SmallGiftInfo();
smallGiftInfo.setUserPhone(awardInfo.getExtMap().get("phone"));
smallGiftInfo.setUserName(awardInfo.getExtMap().get("username"));
smallGiftInfo.setAddress(awardInfo.getExtMap().get("address"));
smallGiftInfo.setOrderId(UUID.randomUUID().toString());
System.out.println("小礼品发放成,请注意查收: " + JSON.toJSON(smallGiftInfo));
return new ResponseResult("200","小礼品发送成功",smallGiftInfo);
}
}
/**
* 优酷 会员服务
**/
public class YouKuMemberFreeGoods implements IFreeGoods {
@Override
public ResponseResult sendFreeGoods(AwardInfo awardInfo) {
String phone = awardInfo.getExtMap().get("phone");
System.out.println("发放优酷会员成功,绑定手机号: " + phone);
return new ResponseResult("200","优酷会员发放成功!");
}
}
优点:封装了创建对象的过程,可以通过参数直接获取对象。把对象的创建和业务逻
辑层分开,这样以后就避免了修改客户代码,如果要实现新产品直接修改工厂
类,而不需要在原代码中修改,这样就降低了客户代码修改的可能性,更加容
易扩展。
缺点:增加新产品时还是需要修改工厂类的代码,违背了“开闭原则”。
概念: 定义一个用于创建对象的接口,让子类决定实例化哪个产品类对象。工厂
方法使一个产品类的实例化延迟到其工厂的子类。
为了提高代码扩展性,我们需要将简单工厂中的if分支逻辑去掉,通过增加抽象工厂(生产工厂的工厂)的方式,让具体工厂去进行实现,由具体工厂来决定实例化哪一个具体的产品对象。
public interface FreeGoodsFactory {
IFreeGoods getInstance();
}
具体工厂
public class DiscountFreeGoodsFactory implements
FreeGoodsFactory {
@Override
public IFreeGoods getInstance() {
return new DiscountFreeGoods();
}
}
public class SmallGiftFreeGoodsFactory implements
FreeGoodsFactory {
@Override
public IFreeGoods getInstance() {
return new SmallGiftFreeGoods();
}
}
Controller
public class DeliverController {
/**
* 按照类型的不同发放商品
*/
public ResponseResult awardToUser(AwardInfo awardInfo){
FreeGoodsFactory freeGoodsFactory = null;
if(awardInfo.getAwardType() == 1){
freeGoodsFactory = new DiscountFreeGoodsFactory();
}else if(awardInfo.getAwardType() == 2){
freeGoodsFactory = new SmallGiftFreeGoodsFactory();
}
IFreeGoods freeGoods = freeGoodsFactory.getInstance();
System.out.println("=====工厂方法模式========");
ResponseResult result = freeGoods.sendFreeGoods(awardInfo);
return result;
}
}
/**
* 工厂的工厂,用来创建工厂类对象.
**/
public class FreeGoodsFactoryMap {
//创建map集合,保存工厂对象
private static final Map<Integer,FreeGoodsFactory> cachedFactories = new HashMap<>();
static{
cachedFactories.put(1,new DiscountFreeGoodsFactory());
cachedFactories.put(2,new SmallGiftFreeGoodsFactory());
}
public static FreeGoodsFactory getParserFactory(Integer type){
if(type == 1){
FreeGoodsFactory freeGoodsFactory = cachedFactories.get(1);
return freeGoodsFactory;
}else if(type == 2){
FreeGoodsFactory freeGoodsFactory = cachedFactories.get(2);
return freeGoodsFactory;
}
return null;
}
}
/**
* 发放奖品接口
**/
public class DeliverController {
//发放奖品
public ResponseResult awardToUser(AwardInfo awardInfo){
//根据类型获取具体工厂
FreeGoodsFactory goodsFactory = FreeGoodsFactoryMap.getParserFactory(awardInfo.getAwardTypes());
//从工厂类中获取对应实例
IFreeGoods iFreeGoods = goodsFactory.getInstance();
System.out.println("==========工厂方法模式=============");
ResponseResult responseResult = iFreeGoods.sendFreeGoods(awardInfo);
return responseResult;
}
}
现在我们的代码已经基本上符合了开闭原则,当有新增的产品时,我们需要做的事
情包括:
优点:
(1)用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程;
(2)在系统增加新的产品时只需要添加具体产品类和对应的具体工厂类,无须对原工厂进行任何修改,满足开闭原则;
缺点:
每增加一个产品就要增加一个具体产品类和一个对应的具体工厂类,这增加了系统的复杂度。
(1)需要使用很多重复代码创建对象时,比如,DAO 层的数据对象、API 层的VO 对象等。
(2)创建对象要访问外部信息或资源时,比如,读取数据库字段,获取访问授权token 信息,配置文件等。
(3)创建需要统一管理生命周期的对象时,比如,会话信息、用户网页浏览轨迹对象等。
(4)创建池化对象时,比如,连接池对象、线程池对象、日志对象等。这些对象的特性是:有限、可重用,使用工厂方法模式可以有效节约资源。
(5)希望隐藏对象的真实类型时,比如,不希望使用者知道对象的真实构造函数参数等。
抽象工厂模式比工厂方法模式的抽象程度更高. 在工厂方法模式中每一个具
体工厂只需要生产一种具体产品,但是在抽象工厂模式中一个具体工厂可以
生产一组相关的具体产品,这样一组产品被称为产品族.产品族中的每一个产
品都分属于某一个产品继承等级结构.
在抽象工厂模式中,每一个具体工厂都提供了多个工厂方法,用于产生多种不同类型的产品.这些产品构成了一个产品族。
抽象工厂
/**
* 抽象工厂: 在一个抽象工厂中可以声明多个工厂方法,用于创建不同类型的产品
**/
public interface AppliancesFactory {
AbstractTV createTV();
AbstractFreezer createFreezer();
}
具体工厂: 每一个具体工厂方法,可以返回一个特定的产品对象,而同一个具体工厂所创建的产品对象构成了一个产品族.
/**
* 具体工厂
**/
public class HairFactory implements AppliancesFactory {
@Override
public AbstractTV createTV() {
return new HairTV();
}
@Override
public AbstractFreezer createFreezer() {
return new HairFreezer();
}
}
public class HisenseFactory implements AppliancesFactory {
@Override
public AbstractTV createTV() {
return new HisenseTV();
}
@Override
public AbstractFreezer createFreezer() {
return new HisenseFreezer();
}
}
抽象产品
public interface AbstractFreezer {}
public interface AbstractTV {}
具体产品
public class HairFreezer implements AbstractFreezer {}
public class HisenseFreezer implements AbstractFreezer {}
public class HairTV implements AbstractTV {}
public class HisenseTV implements AbstractTV {}
/**
* 客户端
**/
public class Client {
private AbstractTV tv;
private AbstractFreezer freezer;
public Client(AppliancesFactory factory){
//在客户端看来就是使用抽象工厂来生产家电
this.tv = factory.createTV();
this.freezer = factory.createFreezer();
}
public AbstractTV getTv() {
return tv;
}
public void setTv(AbstractTV tv) {
this.tv = tv;
}
public AbstractFreezer getFreezer() {
return freezer;
}
public void setFreezer(AbstractFreezer freezer) {
this.freezer = freezer;
}
public static void main(String[] args) {
Client client = new Client(new HisenseFactory());
AbstractTV tv = client.getTv();
System.out.println(tv);
AbstractFreezer freezer = client.getFreezer();
System.out.println(freezer);
}
}