Skip to content

Commit

Permalink
Merge remote-tracking branch 'origin/master'
Browse files Browse the repository at this point in the history
  • Loading branch information
fuzhengwei committed Jun 1, 2024
2 parents e7100fe + 1284044 commit 6f4cd14
Show file tree
Hide file tree
Showing 4 changed files with 36 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ lock: need

`设计模式是可以帮助你改善代码`

很多时候你写出来的`ifelse`都是没有考虑使用设计模式优化,就像同类服务的不同接口适配包装、同类物料不同组合的建造、多种奖品组合的营销工厂等等。它们都可以让你代码中原本使用`if`判断的地方,变成一组组类和面向对象的实现过程。
很多时候你写出来的`ifelse`都是没有考虑使用设计模式优化,就像同类服务的不同接口适配包装、同类物料不同组合的建造、多种奖品组合的营销工厂等等。它们都可以让你代码中原本使用`if`判断的地方,变成一组组类和面向对象的实现过程。

`怎么把设计模式和实际开发结合起来`

Expand Down Expand Up @@ -56,7 +56,7 @@ JDBC多种驱动程序的实现、同品牌类型的台式机和笔记本平板

## 四、案例场景模拟

![场景模拟多种支付和模式](https://bugstack.cn/assets/images/2020/itstack-demo-design-7-02.png)
![场景模拟多种支付和模式](https://bugstack.cn/assets/images/2020/itstack-demo-design-7-02.png)

随着市场的竞争在支付服务行业出现了微信和支付宝还包括一些其他支付服务,但是对于商家来说并不希望改变用户习惯。就像如果我的地摊只能使用微信或者只能使用支付宝付款,那么就会让我顾客伤心,鸡蛋灌饼也卖不动了。

Expand Down Expand Up @@ -121,7 +121,7 @@ public class PayController {
}
```

- 上面的类提供了一个支付服务功能,通过提供的必要字段`用户ID``交易ID``金额``渠道``模式`,来控制支付方式。
- 上面的类提供了一个支付服务功能,通过提供的必要字段`用户ID``交易ID``金额``渠道``模式`,来控制支付方式。
- 以上的`ifelse`应该是最差的一种写法,即使写`ifelse`也是可以优化的方式去写的。

### 3. 测试验证
Expand All @@ -132,26 +132,26 @@ public class PayController {
@Test
public void test_pay() {
PayController pay = new PayController();
System.out.println("\r\n模拟测试场景微信支付、人脸方式。");
System.out.println("\r\n模拟测试场景微信支付、人脸方式。");
pay.doPay("weixin_1092033111", "100000109893", new BigDecimal(100), 1, 2);

System.out.println("\r\n模拟测试场景支付宝支付、指纹方式。");
pay.doPay("jlu19dlxo111","100000109894",new BigDecimal(100), 2, 3);
System.out.println("\r\n模拟测试场景支付宝支付、指纹方式。");
pay.doPay("jlu19dlxo111", "100000109894", new BigDecimal(100), 2, 3);
}
```

- 以上分别测试了两种不同的支付类型和支付模式微信人脸支付、支付宝指纹支付
- 以上分别测试了两种不同的支付类型和支付模式微信人脸支付、支付宝指纹支付

#### 3.2 测试结果

```java
模拟测试场景微信支付、人脸方式。
模拟测试场景微信支付、人脸方式。
23:05:59.152 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付划账开始。uId:weixin_1092033111 tradeId:100000109893 amount:100
23:05:59.155 [main] INFO o.i.demo.design.pay.mode.PayCypher - 人脸支付,风控校验脸部识别
23:05:59.155 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付风控校验。uId:weixin_1092033111 tradeId:100000109893 security:true
23:05:59.155 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付划账成功。uId:weixin_1092033111 tradeId:100000109893 amount:100

模拟测试场景支付宝支付、指纹方式。
模拟测试场景支付宝支付、指纹方式。
23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付划账开始。uId:jlu19dlxo111 tradeId:100000109894 amount:100
23:05:59.156 [main] INFO o.i.demo.design.pay.mode.PayCypher - 指纹支付,风控校验指纹信息
23:05:59.156 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付风控校验。uId:jlu19dlxo111 tradeId:100000109894 security:true
Expand Down Expand Up @@ -197,8 +197,8 @@ itstack-demo-design-7-02

![桥接模式模型结构](https://bugstack.cn/assets/images/2020/itstack-demo-design-7-03.png)

- 左侧`Pay`是一个抽象类,往下是它的两个支付类型实现微信支付、支付宝支付。
- 右侧`IPayMode`是一个接口,往下是它的两个支付模型刷脸支付、指纹支付。
- 左侧`Pay`是一个抽象类,往下是它的两个支付类型实现微信支付、支付宝支付。
- 右侧`IPayMode`是一个接口,往下是它的两个支付模型刷脸支付、指纹支付。
- 那么,`支付类型` × `支付模型` = 就可以得到相应的组合。
- **注意**,每种支付方式的不同,刷脸和指纹校验逻辑也有差异,可以使用适配器模式进行处理,这里不是本文重点不做介绍,可以看适配器模式章节。

Expand All @@ -222,7 +222,7 @@ public abstract class Pay {
}
```

- 在这个类中定义了支付方式的需要实现的划账接口:`transfer`,以及桥接接口`IPayMode`,并在构造函数中用户方自行选择支付方式。
- 在这个类中定义了支付方式的需要实现的划账接口:`transfer`,以及桥接接口`IPayMode`,并在构造函数中用户方自行选择支付方式。
- 如果没有接触过此类实现,可以重点关注 `IPayMode payMode`,这部分是桥接的核心。

#### 2.2 两个支付类型的实现
Expand Down Expand Up @@ -275,7 +275,7 @@ public class ZfbPay extends Pay {
}
```

- 这里分别模拟了调用第三方的两个支付渠道微信、支付宝,当然作为支付综合平台可能不只是接了这两个渠道,还会有其很跟多渠道。
- 这里分别模拟了调用第三方的两个支付渠道微信、支付宝,当然作为支付综合平台可能不只是接了这两个渠道,还会有其很跟多渠道。
- 另外可以看到在支付的时候分别都调用了风控的接口进行验证,也就是不同模式的支付(`刷脸``指纹`),都需要过指定的风控,才能保证支付安全。

#### 2.3 定义支付模式接口
Expand All @@ -288,7 +288,7 @@ public interface IPayMode {
}
```

- 任何一个支付模式刷脸、指纹、密码,都会过不同程度的安全风控,这里定义一个安全校验接口。
- 任何一个支付模式刷脸、指纹、密码,都会过不同程度的安全风控,这里定义一个安全校验接口。

#### 2.4 三种支付模式风控(刷脸、指纹、密码)

Expand Down Expand Up @@ -346,30 +346,30 @@ public class PayCypher implements IPayMode{
```java
@Test
public void test_pay() {
System.out.println("\r\n模拟测试场景微信支付、人脸方式。");
System.out.println("\r\n模拟测试场景微信支付、人脸方式。");
Pay wxPay = new WxPay(new PayFaceMode());
wxPay.transfer("weixin_1092033111", "100000109893", new BigDecimal(100));

System.out.println("\r\n模拟测试场景支付宝支付、指纹方式。");
System.out.println("\r\n模拟测试场景支付宝支付、指纹方式。");
Pay zfbPay = new ZfbPay(new PayFingerprintMode());
zfbPay.transfer("jlu19dlxo111","100000109894",new BigDecimal(100));
}
```

- 与上面的ifelse实现方式相比,这里的调用方式变得整洁、干净、易使用`new WxPay(new PayFaceMode())``new ZfbPay(new PayFingerprintMode())`
- 与上面的ifelse实现方式相比,这里的调用方式变得整洁、干净、易使用`new WxPay(new PayFaceMode())``new ZfbPay(new PayFingerprintMode())`
- 外部的使用接口的用户不需要关心具体的实现,只按需选择使用即可。
- 目前以上优化主要针对桥接模式的使用进行重构`if`逻辑部分,关于调用部分可以使用`抽象工厂``策略模式`配合map结构,将服务配置化。因为这里主要展示`桥接模式`所以就不在额外多加代码,避免喧宾夺主。
- 目前以上优化主要针对桥接模式的使用进行重构`if`逻辑部分,关于调用部分可以使用`抽象工厂``策略模式`配合map结构,将服务配置化。因为这里主要展示`桥接模式`所以就不再额外多加代码,避免喧宾夺主。

#### 3.2 测试结果

```java
模拟测试场景微信支付、人脸方式。
模拟测试场景微信支付、人脸方式。
23:14:40.911 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付划账开始。uId:weixin_1092033111 tradeId:100000109893 amount:100
23:14:40.914 [main] INFO o.i.demo.design.pay.mode.PayCypher - 人脸支付,风控校验脸部识别
23:14:40.914 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付风控校验。uId:weixin_1092033111 tradeId:100000109893 security:true
23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟微信渠道支付划账成功。uId:weixin_1092033111 tradeId:100000109893 amount:100

模拟测试场景支付宝支付、指纹方式。
模拟测试场景支付宝支付、指纹方式。
23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付划账开始。uId:jlu19dlxo111 tradeId:100000109894 amount:100
23:14:40.915 [main] INFO o.i.demo.design.pay.mode.PayCypher - 指纹支付,风控校验指纹信息
23:14:40.915 [main] INFO o.i.demo.design.pay.channel.Pay - 模拟支付宝渠道支付风控校验。uId:jlu19dlxo111 tradeId:100000109894 security:true
Expand All @@ -384,7 +384,7 @@ Process finished with exit code 0

- 通过模拟微信与支付宝两个支付渠道在不同的支付模式下,`刷脸``指纹``密码`,的组合从而体现了桥接模式的在这类场景中的合理运用。简化了代码的开发,给后续的需求迭代增加了很好的扩展性。
- 从桥接模式的实现形式来看满足了单一职责和开闭原则,让每一部分内容都很清晰易于维护和拓展,但如果我们是实现的高内聚的代码,那么就会很复杂。所以在选择重构代码的时候,需要考虑好整体的设计,否则选不到合理的设计模式,将会让代码变得难以开发。
- 任何一种设计模式的选择和使用都应该遵顼符合场景为主,不要刻意使用。而且同一场景但因为业务的复杂不同,从而可能需要使用到多种设计模式的组合,才能将代码设计的更加合理。但这种经验需要从实际的项目中学习经验,并提不断的运用
- 任何一种设计模式的选择和使用都应该遵循符合场景为主,不要刻意使用。而且同一场景因为业务的复杂从而可能需要使用到多种设计模式的组合,才能将代码设计的更加合理。但这种经验需要从实际的项目中学习经验,并能不断的运用



Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ lock: need

`小朋友才做选择题,成年人我都要`

头几年只要群里一问我该学哪个开发语言,哪个语言最好。群里肯定聊的特别火热,有人支持PHP、有人喊号Java、也有C++和C#。但这几年开始好像大家并不会真的`刀枪棍棒、斧钺钩叉`般讨论了,大多数时候都是开玩笑的闹一闹。于此同时在整体的互联网开发中很多时候是一些开发语言公用的,共同打造整体的生态圈。而大家选择的方式也是更偏向于不同领域下选择适合的架构,而不是一味地追求某个语言。这可以给很多初学编程的新人一些提议,不要刻意的觉得某个语言好,某个语言不好,只是在适合的场景下选择最需要的。而你要选择的那个语言可以参考招聘网站的需求量和薪资水平决定。
头几年只要群里一问我该学哪个开发语言,哪个语言最好。群里肯定聊的特别火热,有人支持PHP、有人喊号Java、也有C++和C#。但这几年开始好像大家并不会真的`刀枪棍棒、斧钺钩叉`般讨论了,大多数时候都是开玩笑的闹一闹。与此同时在整体的互联网开发中很多时候是一些开发语言公用的,共同打造整体的生态圈。而大家选择的方式也是更偏向于不同领域下选择适合的架构,而不是一味地追求某个语言。这可以给很多初学编程的新人一些提议,不要刻意的觉得某个语言好,某个语言不好,只是在适合的场景下选择最需要的。而你要选择的那个语言可以参考招聘网站的需求量和薪资水平决定。

`编程开发不是炫技`

Expand Down Expand Up @@ -60,7 +60,7 @@ lock: need

以上是一个非常简化版的营销规则`决策树`,根据`性别``年龄`来发放不同类型的优惠券,来刺激消费起到精准用户促活的目的。

虽然一部分小伙伴可能并没有开发过营销场景,但你可能时时刻刻的被营销着。比如你去经常浏览男性喜欢的机械键盘、笔记本电脑、汽车装饰等等,那么久给你推荐此类的优惠券刺激你消费。那么如果你购物不多,或者钱不在自己手里。那么你是否打过车,有一段时间经常有小伙伴喊,为什么同样的距离他就10元,我就15元呢?其实这些都是被营销的案例,一般对于不常使用软件的小伙伴,经常会进行稍微大力度的促活,增加用户粘性。
虽然一部分小伙伴可能并没有开发过营销场景,但你可能时时刻刻的被营销着。比如你去经常浏览男性喜欢的机械键盘、笔记本电脑、汽车装饰等等,那么就给你推荐此类的优惠券刺激你消费。那么如果你购物不多,或者钱不在自己手里。那么你是否打过车,有一段时间经常有小伙伴喊,为什么同样的距离他就10元,我就15元呢?其实这些都是被营销的案例,一般对于不常使用软件的小伙伴,经常会进行稍微大力度的促活,增加用户粘性。

那么在这里我们就模拟一个类似的决策场景,体现出组合模式在其中起到的重要性。另外,组合模式不只是可以运用于规则决策树,还可以做服务包装将不同的接口进行组合配置,对外提供服务能力,减少开发成本。

Expand Down Expand Up @@ -415,7 +415,7 @@ public class TreeEngineHandle extends EngineBase {
}
```

- 这里对于决策引擎的实现就非常简单了,通过传递进来的必要信息决策树信息、决策物料值,来做具体的树形结构决策。
- 这里对于决策引擎的实现就非常简单了,通过传递进来的必要信息决策树信息、决策物料值,来做具体的树形结构决策。

### 3. 测试验证

Expand Down Expand Up @@ -540,7 +540,7 @@ public void init() {
![树形结构的组织关系](https://bugstack.cn/assets/images/2020/itstack-demo-design-8-04.png)

- **重要**,这一部分是组合模式非常重要的使用,在我们已经建造好的决策树关系下,可以创建出树的各个节点,以及对节点间使用链路进行串联。
- 及时后续你需要做任何业务的扩展都可以在里面添加相应的节点,并做动态化的配置。
- 即使后续你需要做任何业务的扩展都可以在里面添加相应的节点,并做动态化的配置。
- 关于这部分手动组合的方式可以提取到数据库中,那么也就可以扩展到图形界面的进行配置操作。

#### 3.2 编写测试类
Expand Down Expand Up @@ -574,11 +574,11 @@ public void test_tree() {
Process finished with exit code 0
```

- 从测试结果上看这与我们使用`ifelse`是一样的,但是目前这与的组合模式设计下,就非常方便后续的拓展和修改。
- 从测试结果上看这与我们使用`ifelse`是一样的,但是目前这一种组合模式设计下,就非常方便后续的拓展和修改。
- 整体的组织关系框架以及调用决策流程已经搭建完成,如果阅读到此没有完全理解,可以下载代码观察结构并运行调试。

## 七、总结

- 从以上的决策树场景来看,组合模式的主要解决的是一系列简单逻辑节点或者扩展的复杂逻辑节点在不同结构的组织下,对于外部的调用是仍然可以非常简单的。
- 从以上的决策树场景来看,组合模式主要解决的是一系列简单逻辑节点或者扩展的复杂逻辑节点在不同结构的组织下,对于外部的调用是仍然可以非常简单的。
- 这部分设计模式保证了开闭原则,无需更改模型结构你就可以提供新的逻辑节点的使用并配合组织出新的关系树。但如果是一些功能差异化非常大的接口进行包装就会变得比较困难,但也不是不能很好的处理,只不过需要做一些适配和特定化的开发。
- 很多时候因为你的极致追求和稍有倔强的工匠精神,即使在面对同样的业务需求,你能完成出最好的代码结构和最易于扩展的技术架构。`不要被远不能给你指导提升能力的影响到放弃自己的追求!`
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ lock: need

- 图片来自:[https://refactoringguru.cn/design-patterns/decorator](https://refactoringguru.cn/design-patterns/decorator)

初看上图感觉装饰器模式有点像俄罗斯套娃、某众汽车🚕,而装饰器的核心就是再不改原有类的基础上给类新增功能**不改变原有类**,可能有的小伙伴会想到继承、AOP切面,当然这些方式都可以实现,但是使用装饰器模式会是另外一种思路更为灵活,可以避免继承导致的子类过多,也可以避免AOP带来的复杂性。
初看上图感觉装饰器模式有点像俄罗斯套娃、某众汽车🚕,而装饰器的核心就是在不改原有类的基础上给类新增功能**不改变原有类**,可能有的小伙伴会想到继承、AOP切面,当然这些方式都可以实现,但是使用装饰器模式会是另外一种思路更为灵活,可以避免继承导致的子类过多,也可以避免AOP带来的复杂性。

**你熟悉的场景很多用到装饰器模式**

Expand Down Expand Up @@ -197,7 +197,7 @@ Process finished with exit code 0

装饰器主要解决的是直接继承下因功能的不断横向扩展导致子类膨胀的问题,而是用装饰器模式后就会比直接继承显得更加灵活同时这样也就不再需要考虑子类的维护。

在装饰器模式中有四个比较重要点抽象出来的点
在装饰器模式中有四个比较重要点抽象出来的点
1. 抽象构件角色(Component) - `定义抽象接口`
2. 具体构件角色(ConcreteComponent) - `实现抽象接口,可以是一组`
3. 装饰角色(Decorator) - `定义抽象类并继承接口中的方法,保证一致性`
Expand Down Expand Up @@ -246,7 +246,7 @@ public abstract class SsoDecorator implements HandlerInterceptor {
}
```

- 在装饰类中有两个重点的地方是;1)继承了处理接口、2)提供了构造函数、3)覆盖了方法`preHandle`
- 在装饰类中有三个重点的地方是:1)继承了处理接口、2)提供了构造函数、3)覆盖了方法`preHandle`
- 以上三个点是装饰器模式的核心处理部分,这样可以踢掉对子类继承的方式实现逻辑功能扩展。

#### 2.2 装饰角色逻辑实现
Expand Down
Loading

0 comments on commit 6f4cd14

Please sign in to comment.