常用的23种设计模式

分类 设计模式
创建型 工厂方法模式(FactoryMethod)、抽象工厂模式(AbstractFactory)、建造者模式(Builder)、原型模式(Prototype)、单例模式(Singleton)
结构型 适配器模式(Adapter)、桥接模式(Bridge)、组合模式(Composite)、装饰器模式(Decorator)、门面模式(Facade)、享元模式(Flyweight)、代理模式(Proxy)
行为型 解释器模式(Interpreter)、模板方法模式(TemplateMethod)、责任链模式(ChainofResponsibility)、命令模式(Command)、迭代器模式(Iterator)、调解者模式(Mediator)、备忘录模式(Memento)、观察者模式(Observer)、状态模式(State)、策略模式(Strategy)、访问者模式(Visitor)

设计模式之间的关系

1.实现关系:继承抽象类
  用一条带虚线的空心箭头表示

设计模式之间的关系
设计模式之间的关系

2.泛化关系:继承非抽象类
  用一条带实线的空心箭头表示

设计模式之间的关系
设计模式之间的关系

3.聚合关系:用于表示实体对象之间的关系,表示整体由部分构成,其中的整体和部分不是强依赖的,即使整体不存在了,部分仍然存在。
  比如,一辆汽车,它由发动机、轮胎以及其它零件等组成。但是将它拆成各种零件以后,这辆汽车就不存在了,但是发动机、轮胎以及其它零件还是存在的。
 用一条带实线的空心菱形箭头表示

设计模式之间的关系
设计模式之间的关系

4.组合关系:同样表示整体由部分构成的语义,其中的整体和部分是一种强依赖的特殊聚合关系,如果整体不存在了,则部分也不存在了。
比如,如果公司倒闭了,那公司的各个部门也将不存在了。
  用一条带实线的实心菱形箭头表示

设计模式之间的关系
设计模式之间的关系

5.关联关系:描述不同类的对象之间的结构关系。它是一种静态关系,通常与运行状态无关,一般由常识等因素决定的。它一般用来定义 对象之间静态的、天然的结构;所以,关联关系是一种“强关联”的关系。
  比如,有一个类Person它有name、age、id(身份证号码)等属性;另一个类IdCard(身份证类)它有picutre、homeAddr、id(身份证号码)等属性。那么它们的对象可以通过id相互关联起来,具体描述一个人的不同方面。感觉有点像数据库不同表之间,根据字段相关联的意思。
  用一条实线表示

设计模式之间的关系
设计模式之间的关系
  

6.依赖关系:依赖关系描述一个对象在运行期间用到另一个对象的关系;是一种临时性的关系,通常在运行期间产生,并且随着运行时的变 化,依赖关系可能发生变化。依赖也有方向,双向依赖是一种非常糟糕的结构,应该始终保持单向依赖,避免双向依赖。最终代 码中,依赖关系体现为类构造方法和类方法的传入参数,依赖关系除了临时知道对象外,还会使用对方的方法和属性。
用一条带虚线的箭头表示

设计模式之间的关系
设计模式之间的关系

-<作者:小傅哥 链接:https://bugstack.cn 来源:bugstack虫洞栈>
-学习记录用
一:创建型模式
⼯⼚⽅法
抽象⼯⼚
建造者
原型模式
单例模式
1.设计模式原则

设计模式遵循六大原则
单一职责(一个类和方法只做一件事)
里氏替换(多态,子类可扩展父类)
依赖倒置(细节依赖抽象,下层依赖上层)
接口隔离(建立单一接口)
迪米特原则(最少知道,降低耦合)
开闭原则(抽象架构,扩展实现)
会在具体的设计模式章节中,进行体现。

工厂模式

⼯⼚模式⼜称⼯⼚⽅法模式,是⼀种创建型设计模式,其在⽗类中提供⼀个创建对象的⽅法,允许⼦类
决定实例化对象的类型

类型 接口
优惠券 CouponResult sendCoupon(String uId, String couponNumber, String uuid)
实物奖品 Boolean deliverGoods(DeliverReq req)
兑换卡 void grantToken(String bindMobileNumber, String cardId)

3种业务实现,以往我们都是根据不同的业务类型判断,调用不同的接口实现的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
public class PrizeController {
private Logger logger =
LoggerFactory.getLogger(PrizeController.class);
public AwardRes awardToUser(AwardReq req) {
String reqJson = JSON.toJSONString(req);
AwardRes awardRes = null;
try {
logger.info("奖品发放开始{}。req:{}", req.getuId(), reqJson);
// 按照不同类型⽅法商品[1优惠券、2实物商品、3第三⽅兑换卡(爱奇艺)]
if (req.getAwardType() == 1) {
CouponService couponService = new CouponService();
CouponResult couponResult =
couponService.sendCoupon(req.getuId(), req.getAwardNumber(),
req.getBizId());
if ("0000".equals(couponResult.getCode())) {
awardRes = new AwardRes("0000", "发放成功");
} else {
awardRes = new AwardRes("0001",
couponResult.getInfo());
}
} else if (req.getAwardType() == 2) {
GoodsService goodsService = new GoodsService();
DeliverReq deliverReq = new DeliverReq();
deliverReq.setUserName(queryUserName(req.getuId()));

deliverReq.setUserPhone(queryUserPhoneNumber(req.getuId()));
deliverReq.setSku(req.getAwardNumber());
deliverReq.setOrderId(req.getBizId());

deliverReq.setConsigneeUserName(req.getExtMap().get("consigneeUserName"))
;

deliverReq.setConsigneeUserPhone(req.getExtMap().get("consigneeUserPhone"
));

deliverReq.setConsigneeUserAddress(req.getExtMap().get("consigneeUserAddr
ess"));
Boolean isSuccess = goodsService.deliverGoods(deliverReq);
if (isSuccess) {
awardRes = new AwardRes("0000", "发放成功");
} else {
awardRes = new AwardRes("0001", "发放失败");
}
} else if (req.getAwardType() == 3) {
String bindMobileNumber =
queryUserPhoneNumber(req.getuId());
IQiYiCardService iQiYiCardService = new
IQiYiCardService();
iQiYiCardService.grantToken(bindMobileNumber,
req.getAwardNumber());
awardRes = new AwardRes("0000", "发放成功");
}
logger.info("奖品发放完成{}。", req.getuId());
} catch (Exception e) {
logger.error("奖品发放失败{}。req:{}", req.getuId(), reqJson,
e);
awardRes = new AwardRes("0001", e.getMessage());
}
return awardRes;
}
private String queryUserName(String uId) {
return "花花";
}
private String queryUserPhoneNumber(String uId) {
return "15200101232";
}
}

但是一但一个业务会增加处理逻辑,就要在一个方法内添加,判断,处理异常等,违反单一职责,开闭原则
写mock测试时,就会发现调用一个接口的逻辑3遍,写了很多重复代码
工厂模式重构

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
itstack-demo-design-1-02
!"" src
#"" main
$ !"" java
$ !"" org.itstack.demo.design
$ #"" store
$ $ #"" impl
$ $ $ #"" CardCommodityService.java
$ $ $ #"" CouponCommodityService.java
$ $ $ !"" GoodsCommodityService.java
$ $ !"" ICommodity.java
$ !"" StoreFactory.java
!"" test
!"" java
!"" org.itstack.demo.design.test
!"" ApiTest.java

它看上去清晰了、这样分层可以更好扩展了、似乎可以想象到每⼀个类做了什么
定义一个父接口用来实现

1
2
3
4
public interface ICommodity {
void sendCommodity(String uId, String commodityId, String bizId,
Map<String, String> extMap) throws Exception;
}

定义三种业务类型的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
优惠券

public class CouponCommodityService implements ICommodity {
private Logger logger =
LoggerFactory.getLogger(CouponCommodityService.class);
private CouponService couponService = new CouponService();
public void sendCommodity(String uId, String commodityId, String
bizId, Map<String, String> extMap) throws Exception {
CouponResult couponResult = couponService.sendCoupon(uId,
commodityId, bizId);
logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{}
extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[优惠券]:{}", JSON.toJSON(couponResult));
if (!"0000".equals(couponResult.getCode())) throw new
RuntimeException(couponResult.getInfo());
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

public class GoodsCommodityService implements ICommodity {
private Logger logger =
LoggerFactory.getLogger(GoodsCommodityService.class);
private GoodsService goodsService = new GoodsService();
public void sendCommodity(String uId, String commodityId, String
bizId, Map<String, String> extMap) throws Exception {
DeliverReq deliverReq = new DeliverReq();
第三⽅兑换卡
deliverReq.setUserName(queryUserName(uId));
deliverReq.setUserPhone(queryUserPhoneNumber(uId));
deliverReq.setSku(commodityId);
deliverReq.setOrderId(bizId);
deliverReq.setConsigneeUserName(extMap.get("consigneeUserName"));

deliverReq.setConsigneeUserPhone(extMap.get("consigneeUserPhone"));

deliverReq.setConsigneeUserAddress(extMap.get("consigneeUserAddress"));
Boolean isSuccess = goodsService.deliverGoods(deliverReq);
logger.info("请求参数[优惠券] => uId:{} commodityId:{} bizId:{}
extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[优惠券]:{}", isSuccess);
if (!isSuccess) throw new RuntimeException("实物商品发放失败");
}
private String queryUserName(String uId) {
return "花花";
}
private String queryUserPhoneNumber(String uId) {
return "15200101232";
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class CardCommodityService implements ICommodity {
private Logger logger =
LoggerFactory.getLogger(CardCommodityService.class);
// 模拟注⼊
private IQiYiCardService iQiYiCardService = new IQiYiCardService();
public void sendCommodity(String uId, String commodityId, String
bizId, Map<String, String> extMap) throws Exception {
String mobile = queryUserMobile(uId);
iQiYiCardService.grantToken(mobile, bizId);
logger.info("请求参数[爱奇艺兑换卡] => uId:{} commodityId:{} bizId:
{} extMap:{}", uId, commodityId, bizId, JSON.toJSON(extMap));
logger.info("测试结果[爱奇艺兑换卡]:success");
}
private String queryUserMobile(String uId) {


return "15200101232";
}
}

工厂类

1
2
3
4
5
6
7
8
9
10

public class StoreFactory {
public ICommodity getCommodityService(Integer commodityType) {
if (null == commodityType) return null;
if (1 == commodityType) return new CouponCommodityService();
if (2 == commodityType) return new GoodsCommodityService();
if (3 == commodityType) return new CardCommodityService();
throw new RuntimeException("不存在的商品服务类型");
}
}

测试类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

public void test_commodity() throws Exception {
StoreFactory storeFactory = new StoreFactory();
// 1. 优惠券
ICommodity commodityService_1 = storeFactory.getCommodityService(1);
commodityService_1.sendCommodity("10001", "EGM1023938910232121323432",
"791098764902132", null);
// 2. 实物商品
ICommodity commodityService_2 = storeFactory.getCommodityService(2);

Map<String,String> extMap = new HashMap<String,String>();
extMap.put("consigneeUserName", "谢⻜机");
extMap.put("consigneeUserPhone", "15200292123");
extMap.put("consigneeUserAddress", "吉林省.⻓春市.双阳区.XX街道.檀溪苑⼩
区.#18-2109");

commodityService_2.sendCommodity("10001","9820198721311","102300002011222
1113", extMap);
// 3. 第三⽅兑换卡(爱奇艺)
ICommodity commodityService_3 = storeFactory.getCommodityService(3);

commodityService_3.sendCommodity("10001","AQY1xjkUodl8LO975GdfrYUio",null
,null);
}

感觉比较像策略模式吧,但是看过之后确实觉得一些业务代码是可以这么优化,省去很多维护的成本