@@ -3243,8 +3243,171 @@ Comparator<Integer> comparator= (o1, o2) -> {
32433243>
32443244>观察者模式又被称为`发布-订阅(Publish/Subscribe)`,当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
32453245>
3246+
3247+ 访问者模式
3248+
3249+ ```java
3250+ package com.fx.behaviorPattern.observer.d;
3251+
3252+
3253+ import lombok. Data ;
3254+
3255+ import java.util. ArrayList ;
3256+ import java.util. List ;
3257+
3258+ public class Test {
3259+ public static void main (String [] args ) {
3260+ Role role = new Role ();
3261+ role. setName(" 角色" );
3262+ role. setHp(100 );
3263+
3264+ Panel panel = new Panel (role);
3265+ role. addObserver(panel);
3266+
3267+ BallPanel ballPanel = new BallPanel (role);
3268+ role. addObserver(ballPanel);
3269+
3270+ HeadPanel headPanel = new HeadPanel (role);
3271+ role. addObserver(headPanel);
3272+
3273+ Monster monster = new Monster ();
3274+ monster. attack(role);
3275+ monster. attack(role);
3276+ monster. attack(role);
3277+ }
3278+ }
3279+
3280+ @Data
3281+ class Role {
3282+ private String name;
3283+ /**
3284+ * 血量
3285+ **/
3286+ private int hp;
3287+ /**
3288+ * 魔法值(蓝)
3289+ **/
3290+ private int mp;
3291+ /**
3292+ * 所有观察者
3293+ **/
3294+ private List<Observer > observers = new ArrayList<> ();
3295+
3296+ public void addObserver (Observer obj ) {
3297+ observers. add(obj);
3298+ }
3299+
3300+ public void removeObserver (Observer obj ) {
3301+ observers. remove(obj);
3302+ }
3303+
3304+ public void notifyObservers () {
3305+ observers. forEach(Observer :: notifyObserver);
3306+ }
3307+
3308+ public void setHp (int hp ) {
3309+ // 更新血条的时候,一定要通知三个地方:1. 血条、球、面板
3310+ this . hp = hp;
3311+ System . out. println(" 血条更新为:" + hp);
3312+
3313+ System . out. println(" 球形更新为:" + hp);
3314+ System . out. println(" 面板更新为:" + hp);
3315+ }
3316+
3317+ @Override
3318+ public String toString () {
3319+ return " Role{" +
3320+ " name='" + name + ' \' ' +
3321+ " , hp=" + hp +
3322+ " , mp=" + mp +
3323+ ' }' ;
3324+ }
3325+ }
3326+
3327+ class Monster {
3328+ public void attack (Role r ) {
3329+ r. setHp(r. getHp() - 10 );
3330+ r. notifyObservers();
3331+ }
3332+ }
3333+
3334+ /**
3335+ * 观察者们需要一个方法来接收数据
3336+ */
3337+
3338+ interface Observer {
3339+ void notifyObserver ();
3340+ }
3341+
3342+ /**
3343+ * 观察者模式拥有很多变体
3344+ */
3345+ class Panel implements Observer {
3346+ /**
3347+ * 访问者模式其中一种实现就是要持有数据的引用 也就是推拉的形式
3348+ * 推,让数据源推消息给观察者
3349+ * 拉,观察者拉取自己关心的数据
3350+ */
3351+ private final Role r;
3352+
3353+ public Panel (Role r ) {
3354+ this . r = r;
3355+ }
3356+
3357+ @Override
3358+ public void notifyObserver () {
3359+ System . out. printf(" Panel 更新血条了值为:%d\n " , r. getHp());
3360+ }
3361+ }
3362+
3363+ class BallPanel implements Observer {
3364+ private final Role r;
3365+
3366+ public BallPanel (Role r ) {
3367+ this . r = r;
3368+ }
3369+
3370+ @Override
3371+ public void notifyObserver () {
3372+ System . out. printf(" Panel 更新血条了值为:%d\n " , r. getHp());
3373+ }
3374+ }
3375+
3376+ class HeadPanel implements Observer {
3377+ private final Role r;
3378+
3379+ public HeadPanel (Role r ) {
3380+ this . r = r;
3381+ }
3382+
3383+ @Override
3384+ public void notifyObserver () {
3385+ System . out. printf(" Panel 更新血条了值为:%d\n " , r. getHp());
3386+ }
3387+ }
3388+
3389+ ```
3390+
3391+ #### 4.2 . 3 观察者模式总结
3392+
3393+ ! [image-20231105234455568](https:// cdn.fengxianhub.top/resources-master/image-20231105234455568.png)
3394+
3395+
3396+
3397+ ### 4.3 访问者模式
3398+
3399+ >**访问者(Visitor)模式**:封装一些作用于某种数据结构中的各元素的操作,它可以在不改变这个数据结构的前提下定义作用于这些元素的新的操作
3400+ >
32463401>🧨观察者模式的本质是想实现`多重派发 (multiple dispatch)`,由于Java中只有函数参数重载实现的单派发(single dispatch),所以需要这个模式去模拟,如果用支持多派发的语言如clojue或者common lisp、js,就不需要观察者模式了,在golang中也可以通过接口和类型断言来模拟实现多派发。
32473402
3403+ 
3404+
3405+ **抽象访问者(Visitor)角色**:定义接口,声明一个或多个访问操作。
3406+ **具体访问者(ConcreteVisitor)角色**:实现抽象访问者所声明的接口,也就是抽象访问者所声明的各个访问操作。
3407+ **抽象元素(Visitable)角色**:声明一个接受操作,接受一个访问者对象作为一个参数。
3408+ **具体元素结点(ConcreteElement)角色**:实现抽象结点所规定的接受操作。
3409+ **数据结构对象(ObjectStructure)角色**:可以遍历结构中的所有元素,提供一个接口让访问者对象都可以访问每一个元素。
3410+
32483411下面用一个经典的墨子骑马🏇的故事来描述java遇到的多派发的问题
32493412
32503413```java
@@ -3325,7 +3488,7 @@ class BlackHorse implements Horse {}
33253488
33263489如果解决呢?一般有两种做法
33273490
3328- #### 4.2 . 1 类型判断解决多派分发问题
3491+ #### 4.3 . 1 类型判断解决多派分发问题
33293492
33303493在方法里使用`instanceof `判断真实类型,比如(java.awt. Component 的源码)
33313494
@@ -3394,7 +3557,7 @@ protected void processEvent(AWTEvent e) {
33943557
33953558这种方法实现的双重分派都格外的冗长、复杂和容易出错,也不符合`开闭原则`
33963559
3397- #### 4.2 . 2 反转球实现动态分发
3560+ #### 4.3 . 2 反转球实现动态分发
33983561
33993562通过两次的调用来实现,比如下面剪刀石头布的游戏:
34003563
@@ -3509,7 +3672,7 @@ RoshamBol.match()有2个item参数,通关过Item.compete()方法开始2路分
35093672
35103673这种实现也就是“访问者模式”的精华。
35113674
3512- #### 4.2 .4 golang实现多派发
3675+ #### 4.3 .4 golang实现多派发
35133676
35143677```go
35153678package main
@@ -3553,7 +3716,7 @@ func main() {
35533716}
35543717```
35553718
3556- #### 4.2 . 5 js实现多派发
3719+ #### 4.3 . 5 js实现多派发
35573720
35583721```javascript
35593722class Shape {
@@ -3597,7 +3760,7 @@ calculateArea(circle); // 输出:Area: 78.54
35973760calculateArea (rectangle ); // 输出:Area: 12.00
35983761```
35993762
3600- #### 4.2 . 6 java需要借助观察者模式或者访问者模式实现
3763+ #### 4.3 . 6 java需要借助观察者模式或者访问者模式实现
36013764
36023765```java
36033766interface Shape {
@@ -3671,9 +3834,11 @@ public class Main {
36713834}
36723835```
36733836
3837+ ###
3838+
36743839
36753840
3676- ### 4.3 状态机模式
3841+ ### 4.4 状态机模式
36773842
36783843> ** 状态机模式**
36793844>
@@ -3691,7 +3856,7 @@ public class Main {
36913856
36923857打个比方,当订单的状态由待支付变成已支付时,我们需要它能够自动完成例如订单持久化等操作
36933858
3694- #### 4.3 . 1 问题引入
3859+ #### 4.4 . 1 问题引入
36953860
36963861在没有状态机模式之前,我们大概率是直接搞个字段`status`放到表里面,然后在业务代码里面去修改里面的状态,然后在需要用到状态的地方再去查一下db,我们想想这样有哪些弊端?
36973862
@@ -3726,7 +3891,7 @@ public class Main {
37263891
37273892
37283893
3729- #### 4.3 . 2 状态模式解决问题
3894+ #### 4.4 . 3 状态模式解决问题
37303895
37313896
37323897
@@ -3742,7 +3907,7 @@ public class Main {
37423907
37433908
37443909
3745- #### 4.3 .3 市面上的状态机
3910+ #### 4.4 .3 市面上的状态机
37463911
37473912目前开源的状态机实现方案有:
37483913
@@ -3781,13 +3946,13 @@ public class Main {
37813946
37823947
37833948
3784- #### 4.3 .4 spring状态机
3949+ #### 4.4 .4 spring状态机
37853950
37863951https:// www.cnblogs.com/Zero-Jo/p/13891075.html
37873952
37883953
37893954
3790- #### 4.3 .5阿里状态机-cola stateMachine
3955+ #### 4.4 .5阿里状态机-cola stateMachine
37913956
37923957https:// www.cnblogs.com/Zero-Jo/p/14622937.html
37933958
0 commit comments