设计模式—职责链模式(Chain of Responsibility)

news/2024/5/19 15:19:22 标签: 设计模式, 责任链模式, java

目录

思维导图

什么是职责链模式?

有什么优点呢?

有什么缺点呢?

什么场景使用呢?

代码展示

①、职责链模式

②、加薪代码重构


思维导图

什么是职责链模式?

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

我要请假一个月,我发送审批给纪委,但是纪委只能批两小时以内的假,没有权限批假一个月,就需要转交给纪老师,纪老师也没有权限批假一个月,就转交给米老师,这时米老师说“好,准假了”。

这里一层一层的审批就像一条职责链,一个链条,逐层转交自己的请求。

Handler:定义一个处理请示的接口。

ConcreteHandler1:具体处理者类,处理它所负责的请求,可访问它的后继者,如果可处理该请求,就处理它,否则就将该请求转发给它的后继者。

有什么优点呢?

  • 减少类和类之间的联系,降低耦合;
  • 满足迪米特法则

有什么缺点呢?

  • 中介者可能会很多,很复杂

什么场景使用呢?

  • 有多个对象可以处理同一个请求
  • 在不明确指定接收者的情况下,向多个对象中的提交请求
  • 可动态指定一组对象处理请求


代码展示

场景:

①、职责链模式

Handler类,定义一个处理请示的接口

abstract class Handler
{
        protected Handler successor;
        public void SetSuccessor(Handler successor)         //设置继任者
        {
            this.successor = successor;
        }

        public abstract void HandleRequest(int request);    //处理请求的抽象方法
}

ConcreteHandler1类,具体处理者类

class ConcreteHandler1 : Handler
{
        public override void HandleRequest (int request)
        {
            if(request >=0 && request < 10)         //0到10,处理此请求
            {
                Console.WriteLine("{0} 处理请求 {1}", this.GetType().Name, request);
            }else if(successor != null)
            {
                successor.HandleRequest(request);    //转移到下一位
            }
        }
}

ConcreteHandler2类

class ConcreteHandler2 : Handler
{
        public override void HandleRequest(int request)
        {
            if (request >= 10 && request < 20)         //0到10,处理此请求
            {
                Console.WriteLine("{0} 处理请求 {1}", this.GetType().Name, request);
            }
            else if (successor != null)
            {
                successor.HandleRequest(request);    //转移到下一位
            }
        }
}

客户端代码

Handler h1 = new ConcreteHandler1();
Handler h2 = new ConcreteHandler2();
Handler h3 = new ConcreteHandler3();
h1.SetSuccessor(h2);                              //设置职责链的上家与下家
h2.SetSuccessor(h3);

int[] requests = { 2, 5, 14, 22, 18, 3, 27, 20 };

foreach (int request in requests)                 //循环给最小处理者提交请求,不同的数额,有不同权限处理者处理
{
	h1.HandleRequest(request);
}

Console.ReadKey();

②、加薪代码重构

Request类,申请

class Request
{
        //申请类别
        private string requestType;
        public string RequestType
        {
            get { return requestType; }
            set { requestType = value; }
        }

        //申请内容
        private string requestContent;
        public string RequestContent
        {
            get { return requestContent; }
            set { requestContent = value; }
        }

        //数量
        private int number;
        public int Number
        {
            get { return number; }
            set { number = value; }
        }
}

Manager类,管理者

abstract class Manager
{
        protected string name;
        //管理者的上级
        protected Manager superior;
        public Manager(string name)
        {
            this.name = name;
        }

        //设置管理者的上级
        public void SetSuperior(Manager superior)
        {
            this.superior = superior;
        }

        //申请请求
        abstract public void RequestApplications(Request request);
}

CommonManager类,经理

class CommonManager : Manager
{
        public CommonManager(string name) : base(name) { }
        public override void RequestApplications(Request request)
        {
            if (request.RequestType == "请假" && request.Number <= 2)
            {
                Console.WriteLine("{0}:{1} 数量{2} 被批准", name, request.RequestContent, request.Number);
            }
            else
            {
                if (superior != null)
                {
                    superior.RequestApplications(request);
                }
            }
        }
}

Majordomo类,总监

class Majordomo : Manager
{
        public Majordomo(string name) : base(name) { }
        public override void RequestApplications(Request request)
        {
            if (request.RequestType == "请假" && request.Number <= 5)
            {
                Console.WriteLine("{0}:{1} 数量{2} 被批准", name, request.RequestContent, request.Number);
            }
            else
            {
                if (superior != null)
                {
                    superior.RequestApplications(request);
                }
            }
        }
}

GeneralManager类,总经理

class GeneralManager : Manager
{
        public GeneralManager(string name) : base(name) { }
        public override void RequestApplications(Request request)
        {
            if (request.RequestType == "请假" && request.Number <= 5)
            {
                Console.WriteLine("{0}:{1} 数量{2} 被批准", name, request.RequestContent, request.Number);
            }
            else if (request.RequestType == "加薪" && request.Number <= 500)
            {
                Console.WriteLine("{0}:{1} 数量{2} 被批准", name, request.RequestContent, request.Number);
            }
            else if (request.RequestType == "加薪" && request.Number > 500)
            {
                Console.WriteLine("{0}:{1} 数量{2} 再说吧", name, request.RequestContent, request.Number);
            }
        }
}

客户端代码

 CommonManager jinli = new CommonManager("金利");
Majordomo zongjian = new Majordomo("宗剑");
GeneralManager zhongjingli = new GeneralManager("钟精励");
jinli.SetSuperior(zongjian);
zongjian.SetSuperior(zhongjingli);

Request request = new Request();
request.RequestType = "请假";
request.RequestContent="小菜请假";
request.Number = 1;
jinli.RequestApplications(request);

Request request2 = new Request();
request2.RequestType = "请假";
request2.RequestContent = "小菜请假";
request2.Number = 4;
jinli.RequestApplications(request2);

Request request3 = new Request();
request3.RequestType = "加薪";
request3.RequestContent = "小菜请求加薪";
request3.Number = 500;
jinli.RequestApplications(request3);

Request request4 = new Request();
request4.RequestType = "加薪";
request4.RequestContent = "小菜请求加薪";
request4.Number = 1000;
jinli.RequestApplications(request4);

Console.ReadKey();


涉及到的知识点

1、一个类里面有哪些东西?

2、类和实例

什么是类?

就是具有相同的属性和功能的对象的抽象的集合。注意:

  • 类名称首字母大写。多个单词则各个首字母大写;
  • 对外公开的方法需要用‘public’修饰符。

什么是实例?

就是一个真实的对象。比如我们都是‘人’,而你和我其实就是‘人’类的实例了。

什么是实例化?

创建对象的过程,使用new关键字来创建。

Cat cat = new Cat();     //其实做了两件事情

Cat cat;          //第一步、声明一个Cat的对象,对象名为cat
cat = new Cat();  //第二步、将此cat对象实例化

3、字段和属性

什么是字段?

是存储类要满足其设计所需要的数据,字段是与类相关的变量。

private  string  name = "";     //name就是一个字段,私有的类变量

注意

  • 如果在定义字段时,在字段的类型前面使用了readonly关键字,那么字段就为只读字段,它只能在以下两个位置被赋值或者传递到方法中被改变。
  • 在定义字段时赋值;
  • 在类的构造函数内被赋值,或传递到方法中被改变,而且在构造函数中可以被多次赋值。

属性是什么?

是一个方法或一对方法体。提供对类或对象的访问。

属性怎么用呢?

它有两个方法get和set。

get访问器:从属性获取值。返回与声明的属性相同的数据类型,表示的意思是调用时可以得到内部字段的值或引用;

set访问器:为属性赋值。没有显式设置参数,但它有一个隐式参数,用关键字value表示,它的作用是调用属性时可以给内部的字段或引用赋值。

属性有什么作用?

限制外部类对类中成员的访问权限,定义在类级别上。

private int _age;          //年龄
public int Age                    
{
    get                    //也可以直接在属性中进行判断操作、设置限制
    {
        if (_age >= 0 && _age <= 150)     //如果年龄大于 0并且小于150的,(表示输入正确)
        {
        	return _age;                  //则返回输入的年龄
        }
        else                              //否则,(表示输入错误)
        {
         	return 18;                    //返回指定年龄18
        }
     }

    set { _age = value; }
}

静态属性是什么?

在属性前面加static关键字,这个属性就成为了静态属性。

有什么作用呢?

  • 不管类是否有实例,它们都是存在的。
  • 当从类的外部访问时,必须使用类名引用,而不是实例名。
class Person
{
    private static  string name;   //字段
    public static string Name      //属性
    {
        get { return name; }
        set { name = value; }
    }
}
static void Main(string[] args)
{
	Person.Name = "小菜";      //不需要实例化Person类即可直接对属性赋值
}

属性和字段的公有部分解释:

内存:

  • 字段:分配内存
  • 属性:不分配内存

命名规范:

  • 字段:Camel大小写
  • 属性:Pascal小写

4、修饰符

在变量前面可以加上访问修饰符(readonly、static)

readonly(只读):读取该字段的值不能给字段赋值

static:静态字段,可以直接通过类名访问该字段

5、访问修饰符有哪些?

  • public:公有的,对任何类可访问
  • private:私有的,只在类的内部可以访问,成员默认是这个
  • protected:保护的,只允许该类的派生类访问
  • internal:内部的,同一项目所有类可访问                

6、this关键字传递的是什么?

  • 用于区分类的成员和本地变量或参数;
  • 作为调用方法的实参                
//this调用成员变量或成员方法
class Person
{
    private string name;               //字段

    public void setName(string name)    //方法
    {
    	this.name = name;       //将参数值赋予类中的成员变量
    }
    //成员变量和setName()方法中的形式参数的名称相同,都为name,那么如何区分使用的是哪一个变量呢?
    //使用this关键字代表本类对象的引用,this.name指Person类中name成员变量,等号后面的name指传过来的形参name
}
this作为方法的返回值
public Book getBook()
{
    return this;                 //返回Book类引用
}

在getBook()类中,方法的返回值为Book类,所以方法体中使用return this这种形式将Book类的对象返回

this关键字和对象之间有什么关系?

this引用的就是本类的一个对象。

如果省略this会怎么样?

直接写成name=name,只是把形参name赋值给参数变量本身而已,成员变量name的值没有改变            

7、构造方法

  • 什么时候用?就是对类进行初始化(在创建该类的对象时就会调用)。
  • 有哪些特点?与类同名

     无返回值

     不需要void,在new时候调用      

//希望每个小猫一诞生就有姓名
class Cat
{
    private string name ="";        //声明Cat类的私有字符串变量name
    public Cat(string name)         //定义Cat类的构造方法,参数是输入一个字符串
    {
        this.name =name;            //将参数赋值给私有变量name
    }
    
    public string Shout()
    {
        return "我的名字叫"+name+" 喵";
    }
}

注:所有类都有构造方法,如果你不编码则系统默认生成空的构造方法,若有定义的构造方法,那么默认的构造方法就会失效(这个构造方法什么也不做,只是为了让用户能够顺利地实例化)

8、方法重载

是什么?指方法名相同,但参数的数据类型、个数或顺序不同的方法。(一同二不同)

有什么好处?在不改变原方法的基础上,新增功能。

class Animal
{
    private string name;
    
    //方法重载:方法名相同、数据类型、个数/顺序不同
    public Animal(){}          //无参的构造方法
    public Animal(string name) //有参的构造方法
    {
        this.name = name;
    }
}

9、抽象类

什么是抽象类?

目的:抽取相同代码,实现封装思想

特点:

  • 抽象类不能实例化;
  • 抽象方法是必须被子类重写的方法;
  • 如果类中包含抽象方法,那么类就必须定义为抽象类,不论是否还包含其他一般方法

什么是重写?

将父类实现替换为它自己的实现

虚成员

抽象成员

关键字

virtual

abstract

实现体

有实现体

没有实现体,被分号取代

在派生类中被覆写

可重写,也可不重写,使用override

必须被重写,使用override

10、六大原则

六大原则

11、六大关系

六大关系


http://www.niftyadmin.cn/n/4979643.html

相关文章

nginx配置https

1.安装nginx 安装完成后检查 nginx -V2.申请证书与上传 阿里云申请免费的证书 然后上传到某个目录 3.修改nginx配置 #user nobody; worker_processes 1;#error_log logs/error.log; #error_log logs/error.log notice; #error_log logs/error.log info;#pid …

数据结构之树型结构

相关概念树的表示二叉树二叉树性质二叉树储存 实现一颗二叉树创建遍历&#xff08;前中后序&#xff09;获取树中节点个数获取叶子节点个数获取第k层节点个数获取二叉树高度检测值为value元素是否存在层序遍历&#xff08;需要队列来实现&#xff09;判断是否为完全二叉树&…

①matlab的命令掌握

目录 输入命令 命名变量 保存和加载变量 使用内置的函数和常量 输入命令 1.您可以通过在命令行窗口中 MATLAB 提示符 (>>) 后输入命令 任务 使用命令 3*5 将数值 3 和 5 相乘。 答案 3*5 2.除非另有指定&#xff0c;否则 MATLAB 会将计算结果存储在一个名为 ans…

uniapp 项目实践总结(一)uniapp 框架知识总结

导语&#xff1a;最近开发了一个基于 uniapp 框架的项目&#xff0c;有一些感触和体会&#xff0c;所以想记录以下一些技术和经验&#xff0c;在这里做一个系列总结&#xff0c;算是对自己做一个交代吧。 目录 简介全局文件全局组件常用 API条件编译插件开发 简介 uniapp 是…

第 1 章 绪论(计算多项式)

示例代码 1&#xff1a; /* 计算 1 - 1 / x 1 / x * x - ... */#include <stdio.h> #include <sys/timeb.h>int main(void) {double x;int n;printf("Please input x and n: ");scanf_s("%lf%d", &x, &n);struct timeb t1;ftime(&…

dml dql 约束 数据库设计

dml 1.添加数据 *语法 &#xff1a; *insert into 表名&#xff08;列名1&#xff0c;列名2&#xff0c;……..列名n&#xff09;values(值1&#xff0c;值2&#xff0c;…值n) *注意&#xff1a; 1.列名和值要一一对应 2.如果表名后&#xff0c;不写列名&#xff0c;就要给…

k8s之存储篇---数据卷-挂载

挂载是指将定义在 Pod 中的数据卷关联到容器&#xff0c;同一个 Pod 中的同一个数据卷可以被挂载到该 Pod 中的多个容器上。 数据卷内子路径 有时候我们需要在同一个 Pod 的不同容器间共享数据卷。使用 volumeMounts.subPath 属性&#xff0c;可以使容器在挂载数据卷时指向数…

node升级带来的问题及解决方案(digital envelope routines::unsupported)

由于项目需要将 node版本从16升级到了18&#xff0c;但是原有的老项目还是使用的16的环境&#xff0c;导致在运行老版本的时候出现错误 错误信息如下 Error: error:0308010C:digital envelope routines::unsupportedat new Hash (node:internal/crypto/hash:71:19)at Object.…