Unity 设计模式 之 行为型模式 -【中介者模式】【迭代器模式】【解释器模式】
Unity 设计模式 之 行为型模式 -【中介者模式】【迭代器模式】【解释器模式】
目录
Unity 设计模式 之 行为型模式 -【中介者模式】【迭代器模式】【解释器模式】
一、简单介绍
二、中介者模式(Mediator Pattern)
1、什么时候使用中介者模式
2、使用中介者模式的好处
3、使用时的注意事项
三、在 Unity 中使用 中介者模式
1、定义中介者接口
2、实现具体中介者
3、定义角色类
4、定义敌人类
5、创建游戏管理器
6、在 Unity 中测试
7、运行示例
8、示例分析
1、什么时候使用迭代器模式
2、使用迭代器模式的好处
3、使用时的注意事项
五、在 Unity 中使用 迭代器模式
1、定义迭代器接口
2、定义聚合接口
3、定义敌人类
4、实现敌人集合
5、实现具体迭代器
6、创建游戏管理器
7、在 Unity 中测试
8、示例分析
六、解释器模式(Interpreter Pattern)
1、什么时候使用解释器模式
2、使用解释器模式的好处
3、使用时的注意事项
七、在 Unity 中使用 解释器模式
1、定义抽象表达式类
2、实现具体表达式类
3、创建上下文类
4、创建游戏管理器
5、在 Unity 中测试
6、示例分析
一、简单介绍
设计模式 是指在软件开发中为解决常见问题而总结出的一套 可复用的解决方案。这些模式是经过长期实践证明有效的 编程经验总结,并可以在不同的项目中复用。设计模式并不是代码片段,而是对常见问题的 抽象解决方案,它提供了代码结构和模块间交互的一种设计思路,帮助开发者解决特定的设计问题。
设计模式的特点:
- 通用性:设计模式针对的是软件开发中常见的设计问题,适用于各种软件工程项目。
- 可复用性:设计模式可以在不同项目和环境下被重复使用,提高代码的可维护性和扩展性。
- 可扩展性:设计模式有助于让代码结构更加灵活,易于扩展和修改。
- 模块化:通过设计模式,可以减少代码的耦合性,增强模块间的独立性。
- 提高沟通效率:设计模式为开发者提供了一种通用的设计语言,使得团队成员能够快速理解并讨论设计方案。
二、中介者模式(Mediator Pattern)
中介者模式(Mediator Pattern)是一种行为型设计模式,它通过引入一个中介者对象来封装一组对象之间的交互。中介者负责协调这些对象之间的通信,而不是让对象直接引用彼此。这种方式降低了对象之间的耦合度,使得系统更加灵活和易于维护。
1、什么时候使用中介者模式
- 多个对象之间存在复杂交互时:当多个对象相互作用频繁且复杂,直接交互会增加代码的复杂性,适合使用中介者模式。
- 希望简化对象间的通信:当对象间的交互逻辑非常复杂时,使用中介者可以帮助理清思路,集中管理交互逻辑。
- 需要动态改变交互规则时:如果对象的交互逻辑可能发生变化,使用中介者可以在不影响对象本身的情况下,灵活调整交互规则。
2、使用中介者模式的好处
- 降低耦合性:中介者模式将对象之间的直接交互转化为通过中介者的间接交互,减少了对象间的依赖关系,从而降低了耦合度。
- 集中控制交互:所有对象之间的交互逻辑都集中在中介者中,便于管理和修改,增强了系统的可维护性。
- 简化对象之间的交互:通过中介者,可以简化复杂的交互逻辑,使得对象的实现变得更加简单和清晰。
- 提高可扩展性:如果需要新增对象或修改现有对象的交互,只需调整中介者,而无需修改每个对象的实现,提高了系统的灵活性。
3、使用时的注意事项
- 避免中介者过于复杂:中介者的职责应该专注于协调对象之间的交互,避免将过多的逻辑集中在一个类中,以免形成“上帝对象”。
- 简单交互不必使用中介者:对于简单的对象交互,直接通信可能更合适,使用中介者会引入不必要的复杂性。
- 保持中介者的单一职责:确保中介者只负责对象之间的交互,避免将其他职责混合到中介者中,以保持其清晰性和可维护性。
总之,中介者模式通过引入一个中介者对象来集中管理对象之间的交互,降低耦合性,简化系统的复杂性,适用于多对象复杂交互的场景。
三、在 Unity 中使用 中介者模式
在 Unity 中实现 中介者模式 的示例,我们可以创建一个简单的场景,其中多个对象(例如角色、敌人和 UI 元素)通过一个中介者来协调交互。这个示例将演示如何使用中介者模式来处理玩家与敌人之间的交互以及与 UI 的更新。
使用中介者模式协调角色与敌人的交互
参考类图如下:
1、定义中介者接口
首先,我们定义一个中介者接口,描述所有参与者和中介者的基本交互。
public interface IMediator
{
void Notify(object sender, string ev);
}
2、实现具体中介者
接着,我们实现一个具体的中介者类,负责处理角色和敌人之间的交互。
using UnityEngine;
public class GameMediator : IMediator
{
private Player player;
private Enemy enemy;
public GameMediator(Player player, Enemy enemy)
{
this.player = player;
this.enemy = enemy;
}
public void Notify(object sender, string ev)
{
if (ev == "PlayerAttack")
{
enemy.TakeDamage(player.AttackPower);
}
else if (ev == "EnemyAttack")
{
player.TakeDamage(enemy.AttackPower);
}
}
}
3、定义角色类
接下来,我们定义一个角色类,代表玩家,具有攻击和受伤的能力。
using UnityEngine;
public class Player : MonoBehaviour
{
public int Health { get; private set; } = 100;
public int AttackPower { get; private set; } = 20;
private IMediator mediator;
public void SetMediator(IMediator mediator)
{
this.mediator = mediator;
}
public void Attack()
{
Debug.Log("Player attacks!");
mediator.Notify(this, "PlayerAttack");
}
public void TakeDamage(int damage)
{
Health -= damage;
Debug.Log($"Player takes damage: {damage}. Current Health: {Health}");
}
}
4、定义敌人类
同样,我们定义一个敌人类,具有攻击和受伤的能力。
using UnityEngine;
public class Enemy : MonoBehaviour
{
public int Health { get; private set; } = 50;
public int AttackPower { get; private set; } = 10;
private IMediator mediator;
public void SetMediator(IMediator mediator)
{
this.mediator = mediator;
}
public void Attack()
{
Debug.Log("Enemy attacks!");
mediator.Notify(this, "EnemyAttack");
}
public void TakeDamage(int damage)
{
Health -= damage;
Debug.Log($"Enemy takes damage: {damage}. Current Health: {Health}");
}
}
5、创建游戏管理器
我们创建一个游戏管理器类,用于初始化中介者并控制游戏逻辑。
using UnityEngine;
public class GameManager : MonoBehaviour
{
private Player player;
private Enemy enemy;
private GameMediator mediator;
void Start()
{
player = FindObjectOfType<Player>();
enemy = FindObjectOfType<Enemy>();
// 创建中介者并设置参与者
mediator = new GameMediator(player, enemy);
player.SetMediator(mediator);
enemy.SetMediator(mediator);
// 模拟攻击
player.Attack();
enemy.Attack();
}
}
6、在 Unity 中测试
- 创建一个空的 GameObject,命名为 GameManager,并附加
GameManager
脚本。 - 创建一个球体作为玩家对象,附加
Player
脚本。 - 创建一个立方体作为敌人对象,附加
Enemy
脚本。
7、运行示例
在游戏运行时,玩家和敌人会通过中介者进行交互。每当玩家或敌人攻击时,相应的 Notify
方法将被调用,更新各自的生命值并在控制台中输出信息。
8、示例分析
- 中介者(GameMediator):负责协调玩家和敌人之间的交互,处理攻击事件。
- 发起人(Player 和 Enemy):代表参与交互的对象,通过中介者进行通信,避免直接引用彼此。
- 灵活性:通过中介者的引入,我们可以方便地扩展功能,例如添加更多的角色或交互,而无需修改已有对象的实现。
通过这个示例,我们展示了如何在 Unity 中实现 中介者模式,使用中介者来协调对象之间的交互,简化了对象间的通信,提高了系统的可维护性和灵活性。
四、迭代器模式(Iterator Pattern)
迭代器模式(Iterator Pattern)是一种行为型设计模式,它提供了一种方法来顺序访问一个集合对象中的元素,而不需要暴露该对象的内部表示。迭代器模式通常包含两个角色:迭代器(Iterator)和聚合(Aggregate)。迭代器负责遍历集合中的元素,而聚合提供迭代器的接口。
1、什么时候使用迭代器模式
- 需要访问集合对象的元素但不想暴露其内部结构时:例如,封装了复杂数据结构的类,希望对外提供简单的遍历接口。
- 需要在多个遍历中保持独立状态时:当需要同时遍历一个集合的多个迭代器时,迭代器模式能够轻松实现。
- 需要支持不同的遍历方式时:如果集合对象的元素需要按照不同的方式(如正序、倒序)遍历,迭代器模式提供了灵活性。
2、使用迭代器模式的好处
- 封装性:通过迭代器,客户端不需要知道集合的内部结构,避免了对集合实现细节的直接依赖。
- 简化遍历操作:迭代器提供了一种一致的方法来遍历不同类型的集合,客户端代码更加简洁和统一。
- 支持多重遍历:可以同时在一个集合上创建多个迭代器,各自独立地遍历集合,而不影响其他迭代器的状态。
- 易于扩展:如果需要改变集合的遍历方式,只需修改迭代器的实现,而无需修改集合的实现。
3、使用时的注意事项
- 避免过度设计:对于简单的集合,使用迭代器模式可能会导致过度复杂化。在简单情况下,直接使用循环遍历可能更为合适。
- 管理迭代器的生命周期:要注意迭代器的创建和销毁,确保没有资源泄露或意外访问已经释放的对象。
- 性能考虑:如果迭代器的实现涉及到大量的状态管理,可能会影响性能。在性能敏感的场景下,需谨慎使用。
迭代器模式通过提供统一的遍历接口,使得客户端可以在不需要了解集合内部结构的情况下访问元素,提升了系统的封装性和可维护性。它适用于需要遍历复杂集合对象的场景,能够提供灵活的遍历方式。
五、在 Unity 中使用 迭代器模式
在 Unity 中实现 迭代器模式 的示例,我们可以创建一个场景,其中一个自定义集合(例如一个物体池)可以通过迭代器模式进行遍历。这个示例将演示如何使用迭代器模式来管理和遍历游戏中的对象,比如多个敌人。
使用迭代器模式遍历敌人集合
参考类图如下:
1、定义迭代器接口
首先,我们定义一个迭代器接口,描述迭代器的基本操作。
public interface IEnemyIterator
{
bool HasNext();
Enemy Next();
}
2、定义聚合接口
然后,我们定义一个聚合接口,描述如何创建迭代器。
public interface IEnemyCollection
{
IEnemyIterator CreateIterator();
}
3、定义敌人类
接下来,我们定义一个简单的敌人类,表示游戏中的敌人对象。
using UnityEngine;
public class Enemy
{
public string Name { get; set; }
public int Health { get; set; }
public Enemy(string name, int health)
{
Name = name;
Health = health;
}
}
4、实现敌人集合
我们实现一个具体的敌人集合类,用于存储和管理敌人对象,并实现聚合接口。
using System.Collections.Generic;
public class EnemyCollection : IEnemyCollection
{
private List<Enemy> enemies = new List<Enemy>();
public void AddEnemy(Enemy enemy)
{
enemies.Add(enemy);
}
public IEnemyIterator CreateIterator()
{
return new EnemyIterator(this);
}
public int Count => enemies.Count;
public Enemy GetEnemy(int index)
{
return enemies[index];
}
}
5、实现具体迭代器
接下来,实现一个具体的迭代器类,用于遍历敌人集合。
public class EnemyIterator : IEnemyIterator
{
private EnemyCollection collection;
private int currentIndex = 0;
public EnemyIterator(EnemyCollection collection)
{
this.collection = collection;
}
public bool HasNext()
{
return currentIndex < collection.Count;
}
public Enemy Next()
{
return collection.GetEnemy(currentIndex++);
}
}
6、创建游戏管理器
我们创建一个游戏管理器类,用于初始化敌人集合,并使用迭代器遍历敌人。
using UnityEngine;
public class GameManager : MonoBehaviour
{
private EnemyCollection enemyCollection;
void Start()
{
enemyCollection = new EnemyCollection();
// 添加敌人
enemyCollection.AddEnemy(new Enemy("Goblin", 100));
enemyCollection.AddEnemy(new Enemy("Orc", 150));
enemyCollection.AddEnemy(new Enemy("Troll", 200));
// 使用迭代器遍历敌人
IEnemyIterator iterator = enemyCollection.CreateIterator();
while (iterator.HasNext())
{
Enemy enemy = iterator.Next();
Debug.Log($"Enemy: {enemy.Name}, Health: {enemy.Health}");
}
}
}
7、在 Unity 中测试
- 创建一个空的 GameObject,命名为 GameManager,并附加
GameManager
脚本。 - 运行游戏,查看控制台输出的敌人信息。
8、示例分析
- 聚合(EnemyCollection):存储多个敌人对象,并提供创建迭代器的方法。
- 迭代器(EnemyIterator):实现了迭代器接口,负责遍历敌人集合。
- 灵活性:通过迭代器,我们能够方便地遍历敌人集合,且无需了解集合的具体实现。
这个示例展示了如何在 Unity 中实现 迭代器模式,使用迭代器来遍历一个自定义的敌人集合,增强了代码的可读性和可维护性。
六、解释器模式(Interpreter Pattern)
解释器模式(Interpreter Pattern)是一种行为型设计模式,它提供了一种评估语言的语法或表达式的方式。通过定义文法规则和解释这些规则的解释器,可以对输入的句子或表达式进行解析和执行。该模式常用于编写简单的编程语言、表达式解析器或其他需要解析文本的应用程序。
1、什么时候使用解释器模式
- 需要定义文法的上下文时:当需要解析的语言或表达式的语法规则较为复杂,且需要频繁使用时。
- 需要对表达式进行求值时:当程序需要执行或评估某些输入表达式时,例如计算器或简单编程语言的实现。
- 文法相对简单:解释器模式更适用于简单的语法或规则,对于复杂的语言,可能不够灵活或高效。
2、使用解释器模式的好处
- 易于扩展:通过定义新的解释器,可以方便地扩展现有文法,而不需要修改现有代码。
- 清晰的文法表示:可以将复杂的文法规则拆分为简单的组件,使得文法的结构更加清晰。
- 适用于简单语言:对于简单的语法规则和表达式,解释器模式可以有效地提供快速的解析和执行。
3、使用时的注意事项
- 性能考虑:解释器模式可能导致性能问题,尤其是在处理复杂文法或大规模数据时,因为每次解析都可能涉及到许多对象的创建。
- 复杂度:对于复杂的文法,解释器模式的实现可能会变得非常复杂,导致代码难以维护。
- 适用性:对于大型或复杂的语言,可能需要更强大和灵活的解析器,考虑使用其他模式(如组合模式、状态模式)来实现。
解释器模式通过将文法规则和解释逻辑分开,使得程序能够灵活地处理输入表达式,适用于简单语言和表达式的解析。尽管它提供了可扩展性和清晰性,但在复杂语法和性能需求较高的场合,需要谨慎使用。
七、在 Unity 中使用 解释器模式
在 Unity 中实现 解释器模式 的示例,我们可以创建一个简单的计算器,解析和计算数学表达式。这个示例将演示如何使用解释器模式来处理加法和减法操作。
使用解释器模式实现简单计算器
参考类图如下:
1、定义抽象表达式类
首先,我们定义一个抽象的表达式类,所有具体表达式都将继承此类。
public abstract class Expression
{
public abstract int Interpret();
}
2、实现具体表达式类
接着,我们实现具体的表达式类,分别表示数字和运算符。
public class NumberExpression : Expression
{
private int number;
public NumberExpression(int number)
{
this.number = number;
}
public override int Interpret()
{
return number;
}
}
public class AddExpression : Expression
{
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right)
{
this.left = left;
this.right = right;
}
public override int Interpret()
{
return left.Interpret() + right.Interpret();
}
}
public class SubtractExpression : Expression
{
private Expression left;
private Expression right;
public SubtractExpression(Expression left, Expression right)
{
this.left = left;
this.right = right;
}
public override int Interpret()
{
return left.Interpret() - right.Interpret();
}
}
3、创建上下文类
我们可以创建一个上下文类,用于解析输入字符串并构建表达式树。
using System;
using System.Collections.Generic;
public class Context
{
private string input;
public Context(string input)
{
this.input = input;
}
public List<Expression> Parse()
{
List<Expression> expressions = new List<Expression>();
string[] tokens = input.Split(' ');
foreach (string token in tokens)
{
if (int.TryParse(token, out int number))
{
expressions.Add(new NumberExpression(number));
}
else if (token == "+")
{
Expression right = expressions[expressions.Count - 1];
expressions.RemoveAt(expressions.Count - 1);
Expression left = expressions[expressions.Count - 1];
expressions.RemoveAt(expressions.Count - 1);
expressions.Add(new AddExpression(left, right));
}
else if (token == "-")
{
Expression right = expressions[expressions.Count - 1];
expressions.RemoveAt(expressions.Count - 1);
Expression left = expressions[expressions.Count - 1];
expressions.RemoveAt(expressions.Count - 1);
expressions.Add(new SubtractExpression(left, right));
}
}
return expressions;
}
}
4、创建游戏管理器
我们创建一个游戏管理器类,用于初始化上下文并执行计算。
using UnityEngine;
public class GameManager : MonoBehaviour
{
void Start()
{
string expression = "5 3 + 2 -"; // 表达式表示 (5 + 3) - 2
Context context = new Context(expression);
List<Expression> expressions = context.Parse();
// 计算结果
int result = expressions[0].Interpret();
Debug.Log($"Result: {result}");
}
}
5、在 Unity 中测试
- 创建一个空的 GameObject,命名为 GameManager,并附加
GameManager
脚本。 - 运行游戏,查看控制台输出的计算结果。
6、示例分析
- 上下文(Context):负责解析输入字符串并创建表达式树。
- 表达式(Expression):定义抽象表达式及其具体实现(数字、加法、减法)。
- 灵活性:通过添加更多的表达式类,我们可以轻松扩展支持其他操作(如乘法、除法等)。
这个示例展示了如何在 Unity 中实现 解释器模式,通过解析字符串输入并构建表达式树,灵活地计算简单数学表达式。这种模式在需要解析和执行特定语法时非常有用。