行为模式-EP4

ooowl
  • 系统设计
  • 软件工程
  • 设计模式
About 7 min

行为模式-EP4

责任链模式

责任链设计模式(职责链模式)open in new window 责任链是非常常用的模式,一般使用的是单向链条,即顺序处理。也有树形的责任链,根据条件判断但是总是有一条路径。责任链是动态组装的。 当程序需要使用不同方式处理不同种类请求, 而且请求类型和顺序预先未知时, 可以使用责任链模式。当必须按顺序执行多个处理者时, 可以使用该模式。如果所需处理者及其顺序必须在运行时进行改变, 可以使用责任链模式。 比如我要动态的计算优惠,每一种优惠活动的处理都需要计算下一个处理者是谁,这样就需要使用树或者图。Controler需要能够动态的计算链条的函数,但是这么复杂的我没写过,维护起来成本估计也不低。 见到过的责任链比如Nginx里面处理HTTP的handler,核心接到请求之后分别经过server 块选择 location 块选择 日志模块、代理模块等。Scrapy中框架处理结果也是使用责任链插入不同的数据库。Fastapi中中间件使用责任链处理请求
一个简易插入数据库的责任链(虽然做的我自己都不爱用

Click to see more

python


def log_persister(cls):  # 使用元类注册  
    cls()  
    if '__decorators__' not in cls.__dict__:  
        cls.__decorators__ = []  
    cls.__decorators__.append(log_persister)  
    return cls

class ManualLogHandler:  
    """处理手动打印的日志"""  
    chain = []  
  
    def __init__(self, level=-1):  
        self.level = level  
        ManualLogHandler.chain.append(self)  # 添加pipline
        ManualLogHandler.chain.sort(key=lambda x: x.level, reverse=True)  # 按照权重排序
  
    @classmethod  
    def add_to_chain(cls, handler_instance):  
        cls.chain.append(handler_instance)  
  
    @classmethod  
    def handle(cls, message):  
        for handler in cls.chain:  
            handler.process(message)  
  
    def process(self, message):  
        pass


@log_persister  
class PGSysHandler(SystemLogHandler):  
    def process(self, message):  
        db = SessionLocal_CDA()  # 这里可以用数据库连接池的
        system_log = SystemLog(**message)  
        db.add(system_log)  
        db.commit()  
        db.close()

@log_persister  # 用这个装饰器装饰  
class ManualLogStdout(ManualLogHandler):  # 继承Handler类  
    def __init__(self):  
        super().__init__(99)  
  
    def process(self, message):  # 实现处理函数  
        extra_data_j = jsonable_encoder(message['extra_data'])  
        json_str = json.dumps(extra_data_j,ensure_ascii=False)  
        fmt = f"{message['request_id']} | {message['client_ipport']} | {message['logtype']} | {message['http_method']} {message['req_path']} |\n {json_str} \n"  
        logger.bind(system=0).log(message["level"], fmt)



运行结果


Click to see more

C#的官方示例

namespace DesignPatterns;  
  
public interface IHandler  
{  
    IHandler SetNext(IHandler handler);  
  
    object Handle(object request);  
}  
  
// The default chaining behavior can be implemented inside a base handler  
// class.  
abstract class AbstractHandler : IHandler  
{  
    private IHandler _nextHandler;  
  
    public IHandler SetNext(IHandler handler)  
    {        this._nextHandler = handler;  
  
        // Returning a handler from here will let us link handlers in a  
        // convenient way like this:        // monkey.SetNext(squirrel).SetNext(dog);        return handler;  
    }  
    public virtual object Handle(object request)  
    {        if (this._nextHandler != null)  
        {            return this._nextHandler.Handle(request);  
        }        else  
        {  
            return null;  
        }    }}  
  
class MonkeyHandler : AbstractHandler  
{  
    public override object Handle(object request)  
    {        if ((request as string) == "Banana")  
        {            return $"Monkey: I'll eat the {request.ToString()}.\n";  
        }        else  
        {  
            return base.Handle(request);  
        }    }}  
  
class SquirrelHandler : AbstractHandler  
{  
    public override object Handle(object request)  
    {        if (request.ToString() == "Nut")  
        {            return $"Squirrel: I'll eat the {request.ToString()}.\n";  
        }        else  
        {  
            return base.Handle(request);  
        }    }}  
  
class DogHandler : AbstractHandler  
{  
    public override object Handle(object request)  
    {        if (request.ToString() == "MeatBall")  
        {            return $"Dog: I'll eat the {request.ToString()}.\n";  
        }        else  
        {  
            return base.Handle(request);  
        }    }}  
  
class Client  
{  
    //  
    public static void ClientCode(AbstractHandler handler)  
    {        foreach (var food in new List<string> { "Nut", "Banana", "Cup of coffee" }) // 使用泛型的列表  
        {  
            Console.WriteLine($"Client: Who wants a {food}?");  
  
            var result = handler.Handle(food);  
  
            if (result != null)  
            {                Console.Write($"   {result}");  
            }            else  
            {  
                Console.WriteLine($"   {food} was left untouched.");  
            }        }    }}  
  
class ChainOfResponsibility  
{  
    public void Run()  
    {        // 申请责任链  
        var monkey = new MonkeyHandler();  
        var squirrel = new SquirrelHandler();  
        var dog = new DogHandler();  
        //组装责任链  
        monkey.SetNext(squirrel).SetNext(dog); // 在这里组装起来,只是排序,甚至可以单独调用squirrel  
  
        Console.WriteLine("Chain: Monkey > Squirrel > Dog\n");  
        Client.ClientCode(monkey);  
        Console.WriteLine();  
  
        Console.WriteLine("Subchain: Squirrel > Dog\n");  
        Client.ClientCode(squirrel);  
    }}

运行结果

Chain: Monkey > Squirrel > Dog

Client: Who wants a Nut?
   Squirrel: I'll eat the Nut.
Client: Who wants a Banana?
   Monkey: I'll eat the Banana.
Client: Who wants a Cup of coffee?
   Cup of coffee was left untouched.

命令模式

命令设计模式open in new window 适用于请求 组合 参数化 顺序 撤回等操作。

Click to see more

运行结果


与适配器模式异同:

  • 应用场景不同
    • 命令模式适用于需要将操作请求封装为对象,并且需要支持操作的撤销和重做、请求排队和日志记录的场景。
    • 适配器模式适用于需要使用一个已经存在的类,但其接口不符合当前需求的情况。
  • 实现方式不同
    • 在命令模式中,命令对象包含执行操作的方法,调用者通过调用命令对象的方法来执行操作。
    • 在适配器模式中,适配器类实现目标接口,通过调用被适配者的方法来实现目标接口的方法。

迭代器模式

中介者模式

备忘录模式

观察者模式

比较依赖C#中的委托,如果使用python这种, 就是实现了一个订阅机制, 可在对象事件发生时通知多个 “观察” 该对象的其他对象

  1. 一个用于存储订阅者对象引用的列表成员变量;
    • 订阅者需要实现统一的接收订阅的接口,接口中必须声明通知方法及其参数
    • tips:可使用C#的接口实现试试
  2. 几个用于添加或删除该列表中订阅者的公有方法。
    • 发布者必须仅通过订阅者接口与它们进行交互
    • 将订阅逻辑放入一个独立的对象, 上下文也可以放进去,然后让所有实际订阅者使用该对象,而不是直接用发布者去操作订阅者 订阅者的通知顺序是随机的。C#中的委托执行顺序是绑定顺序,所以不要往订阅者传可变的引用对象,不安全。
Click to see more
namespace DesignPatterns;  
  
//教程给的是猫鼠  
public class Animal  
{  
    protected string Name;  
  
    public Animal(string name)  
    {        this.Name = name;  
    }}  
  
  
public class Cat : Animal  
{  
    public delegate void Publisher(); // 声明函数指针类型  
  
    public Publisher come_publisher; // 声明函数指针变量  
  
    public Cat(string name):base(name)  
    {        Console.WriteLine($"Create a Cat {name}");  
    }  
    public void ComeThere()  
    {        Console.WriteLine($"{Name} Cat come there");  
        come_publisher?.Invoke();  
    }  
}  
  
public class Mouse : Animal  
{  
    public Mouse(string name,Cat c):base(name)  
    {        Console.WriteLine($"Create a Mouse {name}");  
        c.come_publisher += Run; // 在管理对象中注册  
    }  
  
  
  
    public void Run()  
    {        Console.WriteLine($"{Name} Mouse runing ");  
    }}
class Program  
{  
    static void Main(string[] args)  
    {   
        Console.WriteLine("-----------------观察者模式-----------------");  
        // 猫鼠模型  
        Cat c = new Cat("好猫");  
        Mouse m1 = new Mouse("鼠1",c);  
        Mouse m2 = new Mouse("鼠2",c);  
        Mouse m3 = new Mouse("鼠3",c);  
        c.ComeThere();  
        
    }  
}

运行结果

-----------------观察者模式-----------------
Create a Cat 好猫
Create a Mouse 鼠1
Create a Mouse 鼠2
Create a Mouse 鼠3
好猫 Cat come there
鼠1 Mouse runing 
鼠2 Mouse runing 
鼠3 Mouse runing 


状态模式

策略模式

策略设计模式open in new window 策略模式是让代码更松耦合的方式,提前预判代码会比较复杂会有多种方式采取的策略。其实就是原先分各个函数会把一个类弄的过于复杂,就拆分多个工具类使用多态单独处理。策略使用接口和多态实现添加新的策略处理类的时候不需要动原先的代码,只需要传入新的策略类就可以了

Click to see more
namespace DesignPatterns;  
  
class Context  
{  
    private IStrategy _strategy;  
  
    public Context()  
    { }  
    public Context(IStrategy strategy)  
    {        this._strategy = strategy;  
    }  
    public void SetStrategy(IStrategy strategy)  //  设置策略处理类  
    {  
        this._strategy = strategy;  
    }  
    public void DoSomeBusinessLogic()  
    {        Console.WriteLine("Context: Sorting data using the strategy (not sure how it'll do it)");  
        var result = this._strategy.DoAlgorithm(new List<string> { "a", "b", "c", "d", "e" }); //  添加新的策略的时候不需要更改此代码,此处同时也是多态的体现  
  
        string resultStr = string.Empty;  
        foreach (var element in result as List<string>)  
        {            resultStr += element + ",";  
        }  
        Console.WriteLine(resultStr);  
    }}  
  
public interface IStrategy // 声明了接口  
{  
    object DoAlgorithm(object data);  //  声明接口函数  
}  
  
class ConcreteStrategyA : IStrategy  //  继承接口  
{  
    public object DoAlgorithm(object data)  
    {        var list = data as List<string>; //  转型一下  
        list.Sort();  
  
        return list;  
    }}  
  
class ConcreteStrategyB : IStrategy  
{  
    public object DoAlgorithm(object data)  
    {        var list = data as List<string>;  
        list.Sort();  
        list.Reverse();  
  
        return list;  
    }}  
  
class StrategyPatterns  
{  
    public void Run()  
    {        var context = new Context();  
  
        Console.WriteLine("Client: Strategy is set to normal sorting.");  
        context.SetStrategy(new ConcreteStrategyA());  
        context.DoSomeBusinessLogic();  
  
        Console.WriteLine();  
  
        Console.WriteLine("Client: Strategy is set to reverse sorting.");  
        context.SetStrategy(new ConcreteStrategyB());  
        context.DoSomeBusinessLogic();  
    }}

运行结果


模板方法模式

访问者模式

Loading...