9.职责链模式

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

×

喜欢就点赞,疼爱就打赏