9.行为型模式-职责链模式
9.1 基础知识
学习难度:3
使用频率:2
总分:5
定义
职责链模式(Chain of Responsibility Pattern)使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。
说人话
给对象设置继任者,处理时选择自己处理或者传给继任者处理。
结构图
实现步骤
- 抽象处理者类:定义同为抽象处理者接口类型对象,称之为继任者。定义设置继任者方法,外部传入继任者。定义处理请求抽象方法,传入请求。
- 具体处理者类:继承抽象处理者类。实现处理请求抽象方法,自定义逻辑处理请求或传给继任者处理。
- 客户端:实例化多个具体处理者。设置其中某些具体处理者的继任者。调用具体处理者的处理请求。
说明
职责链模式允许请求者不必知道谁将处理请求,请求会被沿着链传递,直到有一个处理者能够处理它。这样可以使系统更灵活,并且降低了对象之间的耦合度。
9.2 模版代码
抽象处理者和具体处理者
// 抽象处理者
abstract class Handler
{
protected Handler successor;
public void SetSuccessor(Handler successor)
{
this.successor = successor;
}
public abstract void HandleRequest(int request);
}
// 具体处理者1
class ConcreteHandler1 : Handler
{
public override void HandleRequest(int request)
{
if (request <= 10)
{
Console.WriteLine("具体处理者1 处理请求:" + request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
// 具体处理者2
class ConcreteHandler2 : Handler
{
public override void HandleRequest(int request)
{
if (request > 10 && request <= 20)
{
Console.WriteLine("具体处理者2 处理请求:" + request);
}
else if (successor != null)
{
successor.HandleRequest(request);
}
}
}
客户端
class Program
{
static void Main()
{
// 创建处理者对象
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
// 设置处理者的继任者
handler1.SetSuccessor(handler2);
// 发起请求
int[] requests = { 5, 12, 25, 7, 18 };
foreach (int request in requests)
{
handler1.HandleRequest(request);
// 具体处理者1 处理请求:5
// 具体处理者2 处理请求:12
// 具体处理者1 处理请求:7
// 具体处理者2 处理请求:18
}
}
}
9.3 CSharp实践
实践需求
使用职责链模式,实现和领导请假的流程。
请假申请类
// 请假申请类
class LeaveRequest
{
public string Applicant { get; set; } // 申请人
public int Days { get; set; } // 请假天数
public LeaveRequest(string applicant, int days)
{
Applicant = applicant;
Days = days;
}
}
抽象处理者和具体处理者
// 抽象处理者
abstract class Approver
{
protected Approver successor; // 下一个处理者
public void SetSuccessor(Approver successor)
{
this.successor = successor;
}
//处理请假请求
public abstract void ProcessRequest(LeaveRequest request);
}
// 具体处理者 - 组长
class TeamLead : Approver
{
public override void ProcessRequest(LeaveRequest request)
{
if (request.Days <= 2)
{
Console.WriteLine($"组长批准 {request.Applicant} 的请假申请,天数:{request.Days}");
}
else if (successor != null)
{
Console.WriteLine("请假天数较长,无法由组长批准,交由下一级处理者。");
successor.ProcessRequest(request); // 传递给下一个处理者
}
else
{
Console.WriteLine($"请假天数太长,没有合适的处理者,申请不予批准。");
}
}
}
// 具体处理者 - 经理
class Manager : Approver
{
public override void ProcessRequest(LeaveRequest request)
{
if (request.Days <= 5)
{
Console.WriteLine($"经理批准 {request.Applicant} 的请假申请,天数:{request.Days}");
}
else if (successor != null)
{
Console.WriteLine("请假天数较长,无法由经理批准,交由总经理处理。");
successor.ProcessRequest(request); // 传递给总经理处理
}
else
{
Console.WriteLine($"请假天数太长,没有合适的处理者,申请不予批准。");
}
}
}
// 具体处理者 - 总经理
class GeneralManager : Approver
{
public override void ProcessRequest(LeaveRequest request)
{
Console.WriteLine($"总经理批准 {request.Applicant} 的请假申请,天数:{request.Days}");
}
}
客户端
class Program
{
static void Main()
{
// 创建处理者对象
Approver teamLead = new TeamLead(); // 创建组长处理者
Approver manager = new Manager(); // 创建经理处理者
Approver generalManager = new GeneralManager(); // 创建总经理处理者
// 设置处理者的继任者关系
teamLead.SetSuccessor(manager); // 组长的继任者是经理
manager.SetSuccessor(generalManager); // 经理的继任者是总经理
// 创建请假申请
LeaveRequest request1 = new LeaveRequest("张三", 1); // 申请1天的请假
LeaveRequest request2 = new LeaveRequest("李四", 3); // 申请3天的请假
LeaveRequest request3 = new LeaveRequest("王五", 7); // 申请7天的请假
// 提交请假申请并让处理者处理
teamLead.ProcessRequest(request1); // 组长处理请假申请1
teamLead.ProcessRequest(request2); // 组长处理请假申请2,但需要经过经理审批
teamLead.ProcessRequest(request3); // 组长处理请假申请3,但需要经过经理和总经理的审批
}
}
9.4 Unity实践
实践需求
使用职责链模式,让狗头,剑圣和薇恩形成三角阵,随机生成一个敌方英雄,让三者的随机一人攻击敌方英雄,假如敌方英雄和己方攻击者英雄相同要传递给下一个攻击者。
英雄处理抽象类和具体英雄处理类
public abstract class HeroHandler : MonoBehaviour
{
protected Animator animator;
private void Awake()
{
// 获取与英雄相关的Animator组件
animator = this.gameObject.GetComponent<Animator>();
}
protected HeroHandler successor;
public void SetSuccessor(HeroHandler successor)
{
// 设置下一个处理器,即在职责链中的下一个英雄
this.successor = successor;
}
public abstract void HandleRequest(HeroHandler heroHandler);
// 定义一个抽象方法,用于处理请求的具体逻辑,由具体的英雄子类来实现
}
public class DogHandler : HeroHandler
{
public override void HandleRequest(HeroHandler heroHandler)
{
if (heroHandler.GetType() != this.GetType())
{
transform.LookAt(heroHandler.gameObject.transform.position);
if (animator != null)
{
animator.SetTrigger("attack");
}
Debug.Log("对象不是我的同类狗头,使用法天象地打你");
}
else if (successor != null)
{
Debug.Log($"这是我的同类,叫给{successor.name}来打吧");
successor.HandleRequest(heroHandler);
}
}
}
public class VayneHandler : HeroHandler
{
public override void HandleRequest(HeroHandler heroHandler)
{
if (heroHandler.GetType() != this.GetType())
{
transform.LookAt(heroHandler.gameObject.transform.position);
if (animator != null)
{
animator.SetTrigger("attack");
}
Debug.Log("对象不是我的同类薇恩,使用闪避突袭打你");
}
else if (successor != null)
{
Debug.Log($"这是我的同类,叫给{successor.name}来打吧");
successor.HandleRequest(heroHandler);
}
}
}
public class YiHandler : HeroHandler
{
public override void HandleRequest(HeroHandler heroHandler)
{
if (heroHandler.GetType() != this.GetType())
{
transform.LookAt(heroHandler.gameObject.transform.position);
if (animator != null)
{
animator.SetTrigger("attack");
}
Debug.Log("对象不是我的同类剑圣,使用阿尔法突袭打你");
}
else if (successor != null)
{
Debug.Log($"这是我的同类,叫给{successor.name}来打吧");
successor.HandleRequest(heroHandler);
}
}
}
客户端
public class TestChainOfResponsibilityPattern : MonoBehaviour
{
// 定义处理请求的不同英雄的处理器
public HeroHandler dogHandler;
public HeroHandler yiHandler;
public HeroHandler vayneHandler;
// 存储所有英雄的处理器
public List<HeroHandler> heroHandlers;
// 存储不同英雄的游戏对象
public GameObject[] heroGameObjects;
private GameObject enemy;
private void Start()
{
// 设置处理请求的职责链顺序,这里构建一个循环链
dogHandler.SetSuccessor(yiHandler);
yiHandler.SetSuccessor(vayneHandler);
vayneHandler.SetSuccessor(dogHandler);
// 将处理器添加到处理器列表中
heroHandlers.Add(dogHandler);
heroHandlers.Add(yiHandler);
heroHandlers.Add(vayneHandler);
// 启动协程来生成敌人并交给不同的英雄处理
StartCoroutine(RandomCreateEnemy());
}
IEnumerator RandomCreateEnemy()
{
while (true)
{
// 销毁之前的敌人
if (enemy != null) Destroy(enemy);
// 随机选择一个英雄对象生成敌人
int index = Random.Range(0, heroGameObjects.Length);
enemy = Instantiate(heroGameObjects[index], GenerateRandomVectorInSquare(-5f, 5f), Quaternion.identity);
Debug.Log("生成了敌人" + enemy.name);
// 随机选择一个英雄处理器来处理敌人
int index2 = Random.Range(0, heroHandlers.Count);
Debug.Log("交给你来打" + heroHandlers[index2].name);
heroHandlers[index2].HandleRequest(enemy.GetComponentInChildren<HeroHandler>());
yield return new WaitForSeconds(1f);
// 销毁敌人并等待一段时间再生成新的敌人
if (enemy != null) Destroy(enemy);
yield return new WaitForSeconds(4f);
}
}
// 生成一个随机位置的三维向量
Vector3 GenerateRandomVectorInSquare(float min, float max)
{
float randomX = Random.Range(min, max);
float randomZ = Random.Range(min, max);
Vector3 randomVector = new Vector3(randomX, 0f, randomZ);
return randomVector;
}
}
运行结果
转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 785293209@qq.com