mirror of
https://github.com/youthlql/JavaYouth.git
synced 2026-03-13 21:33:42 +08:00
更新所有文章的图床,旧图床由于一些原因可能会逐渐失效
This commit is contained in:
@@ -8,7 +8,7 @@ categories:
|
||||
- 05.行为型
|
||||
keywords: 状态模式,迭代器模式
|
||||
description: 看文章
|
||||
cover: 'https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/logo.jpg'
|
||||
cover: 'https://gitee.com/youthlql/randombg/raw/master/logo/design_patterns.jpg'
|
||||
abbrlink: 877f4ef2
|
||||
date: 2021-08-02 15:51:58
|
||||
---
|
||||
@@ -30,7 +30,7 @@ date: 2021-08-02 15:51:58
|
||||
4. 实际上,马里奥形态的转变就是一个状态机。其中,马里奥的不同形态就是状态机中的“状态”,游戏情节(比如吃了蘑菇)就是状态机中的“事件”,加减积分就是状态机中的“动作”。比如,吃蘑菇这个事件,会触发状态的转移:从小马里奥转移到超级马里奥,以及触发动作的执行(增加 100 积分)。
|
||||
5. 为了方便接下来的讲解,我对游戏背景做了简化,只保留了部分状态和事件。简化之后的状态转移如下图所示:
|
||||
|
||||
<img src="https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/behavior_type/05.03/0001.png"/>
|
||||
<img src="https://img.imlql.cn/youthlql@1.0.0/design_patterns/behavior_type/05.03/0001.png"/>
|
||||
|
||||
|
||||
|
||||
@@ -180,7 +180,7 @@ public class MarioStateMachine {
|
||||
1. 实际上,上面这种实现方法有点类似 hard code,对于复杂的状态机来说不适用,而状态机的第二种实现方式查表法,就更加合适了。接下来,我们就一块儿来看下,如何利用查表法来补全骨架代码。
|
||||
2. 实际上,除了用状态转移图来表示之外,状态机还可以用二维表来表示,如下所示。在这个二维表中,第一维表示当前状态,第二维表示事件,值表示当前状态经过事件之后,转移到的新状态及其执行的动作。
|
||||
|
||||
<img src="https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/behavior_type/05.03/0002.png"/>
|
||||
<img src="https://img.imlql.cn/youthlql@1.0.0/design_patterns/behavior_type/05.03/0002.png"/>
|
||||
|
||||
3. 相对于分支逻辑的实现方式,查表法的代码实现更加清晰,可读性和可维护性更好。当修改状态机时,我们只需要修改 transitionTable 和 actionTable 两个二维数组即可。实际上,如果我们把这两个二维数组存储在配置文件中,当需要修改状态机时,我们甚至可以不修改任何代码,只需要修改配置文件就可以了。具体的代码如下所示:
|
||||
|
||||
@@ -511,7 +511,7 @@ public class MarioStateMachine {
|
||||
2. 在开篇中我们讲到,它用来遍历集合对象。这里说的“集合对象”也可以叫“容器”“聚合对象”,实际上就是包含一组对象的对象,比如数组、链表、树、图、跳表。迭代器模式将集合对象的遍历操作从集合类中拆分出来,放到迭代器类中,让两者的职责更加单一。
|
||||
3. 迭代器是用来遍历容器的,所以,一个完整的迭代器模式一般会涉及**容器和容器迭代器**部分两部分内容。为了达到基于接口而非实现编程的目的,容器又包含容器接口、容器实现类,迭代器又包含迭代器接口、迭代器实现类。对于迭代器模式,我画了一张简单的类图,你可以看一看,先有个大致的印象。
|
||||
|
||||
<img src="https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/behavior_type/05.03/0003.png">
|
||||
<img src="https://img.imlql.cn/youthlql@1.0.0/design_patterns/behavior_type/05.03/0003.png">
|
||||
|
||||
|
||||
|
||||
@@ -629,7 +629,7 @@ public class Demo {
|
||||
2. 结合刚刚的例子,我们来总结一下迭代器的设计思路。总结下来就三句话:迭代器中需要定义 hasNext()、currentItem()、next() 三个最基本的方法。待遍历的容器对象通过依赖注入传递到迭代器类中。容器通过 iterator() 方法来创建迭代器。
|
||||
3. 这里我画了一张类图,如下所示。实际上就是对上面那张类图的细化,你可以结合着一块看。
|
||||
|
||||
<img src="https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/behavior_type/05.03/0004.png"/>
|
||||
<img src="https://img.imlql.cn/youthlql@1.0.0/design_patterns/behavior_type/05.03/0004.png"/>
|
||||
|
||||
|
||||
|
||||
@@ -752,7 +752,7 @@ public class Demo {
|
||||
4. 为了保持数组存储数据的连续性,数组的删除操作会涉及元素的搬移。当执行到第 57 行代码的时候,我们从数组中将元素 a 删除掉,b、c、d 三个元素会依次往前搬移一位,这就会导致游标本来指向元素 b,现在变成了指向元素 c。原本在执行完第 56 行代码之后,我们还可以遍历到 b、c、d 三个元素,但在执行完第 57 行代码之后,我们只能遍历到 c、d 两个元素,b 遍历不到了。
|
||||
5. 对于上面的描述,我画了一张图,你可以对照着理解。
|
||||
|
||||
<img src="https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/behavior_type/05.03/0005.png"/>
|
||||
<img src="https://img.imlql.cn/youthlql@1.0.0/design_patterns/behavior_type/05.03/0005.png"/>
|
||||
|
||||
6. 不过,如果第 57 行代码删除的不是游标前面的元素(元素 a)以及游标所在位置的元素(元素 b),而是游标后面的元素(元素 c 和 d),这样就不会存在任何问题了,不会存在某个元素遍历不到的情况了。
|
||||
7. 所以,我们前面说,在遍历的过程中删除集合元素,结果是不可预期的,有时候没问题(删除元素 c 或 d),有时候就有问题(删除元素 a 或 b),这个要视情况而定(到底删除的是哪个位置的元素),就是这个意思。
|
||||
@@ -778,7 +778,7 @@ public class Demo {
|
||||
10. 跟删除情况类似,如果我们在游标的后面添加元素,就不会存在任何问题。所以,在遍历的同时添加集合元素也是一种不可预期行为。
|
||||
11. 同样,对于上面的添加元素的情况,我们也画了一张图,如下所示,你可以对照着理解。
|
||||
|
||||
<img src="https://unpkg.zhimg.com/youthlql@1.0.0/design_patterns/behavior_type/05.03/0006.png"/>
|
||||
<img src="https://img.imlql.cn/youthlql@1.0.0/design_patterns/behavior_type/05.03/0006.png"/>
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user