C# .Net设计模式与代码实现(三)——行为型模式

行为型模式


1、模板方法模式

场景:
确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。

定义:
定义一个抽象的算法骨架,而将算法的一些步骤延迟到子类中。

目的:
在步奏确定的情况下,扩展可变部分,并满足开闭原则。

代码示例:

/// <summary>
/// 模板方法
/// </summary>
public class TemplateMethod
{
    /// <summary>
    /// 抽象模板方法类
    /// </summary>
    public abstract class PrintInfo
    {
        /// <summary>
        /// 打印信息
        /// </summary>
        /// <remarks>模板方法</remarks>
        public void Print()
        {
            var name = GetName();
            var age = GetAge();

            Console.WriteLine($"Name:\t{name}");
            Console.WriteLine($"Age:\t{age}");
        }

        /// <summary>
        /// 获取名称
        /// </summary>
        /// <remarks>子类实现</remarks>
        /// <returns></returns>
        public abstract string GetName();

        /// <summary>
        /// 获取年龄
        /// </summary>
        /// <remarks>子类实现</remarks>
        /// <returns></returns>
        public abstract int GetAge();
    }

    /// <summary>
    /// 小明信息打印类
    /// </summary>
    /// <remarks>具体子类</remarks>
    public class XiaoMingPrintInfo : PrintInfo
    {
        public override int GetAge()
        {
            return 11;
        }

        public override string GetName()
        {
            return "小明";
        }
    }

    /*
        调用方式:
        PrintInfo printInfo = new XiaoMingPrintInfo();
        printInfo.Print();
     */
}

2、策略模式

场景:
在同一个环境下需要不同的策略。

定义:
在同一个环境下,将不同算法封装起来,使它们可以相互替换,且算法的变化不会影响使用调用者。

目的:
相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的策略。

代码示例:

/// <summary>
/// 策略模式
/// </summary>
public class Strategy
{
    /// <summary>
    /// 抽象图表
    /// </summary>
    /// <remarks>抽象策略</remarks>
    public interface IChart
    {
        /// <summary>
        /// 渲染图表
        /// </summary>
        public void Render();
    }

    /// <summary>
    /// 饼图
    /// </summary>
    /// <remarks>具体策略类</remarks>
    public class PieChart : IChart
    {
        public void Render()
        {
            Console.WriteLine("Render PieChart");
        }
    }

    /// <summary>
    /// 线图
    /// </summary>
    /// <remarks>具体策略类</remarks>
    public class LineChart : IChart
    {
        public void Render()
        {
            Console.WriteLine("Render LineChart");
        }
    }

    /// <summary>
    /// 渲染环境类
    /// </summary>
    public class RenderContext
    {
        /// <summary>
        /// 实现图表对象
        /// </summary>
        public IChart Chart { get; set; }

        public void SetChart(IChart Chart)
        {
            this.Chart = Chart;
        }

        /// <summary>
        /// 执行当前图表对象渲染
        /// </summary>
        public void Render()
        {
            this.Chart.Render();
        }
    }

    /*
        调用方式:
        RenderContext context = new RenderContext();
        context.SetChart(new PieChart());
        context.Render();
     */
}

3、命令模式

场景:
在调用的前后需要添加不确定的代码,并满足开闭原则。

定义:
将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。

目的:
将请求与调用解耦,方便在调用前后做功能添加,类似于AOP。

代码示例:

/// <summary>
/// 命令模式
/// </summary>
public class Command
{
    /// <summary>
    /// 命令抽象
    /// </summary>
    public interface ICommand
    {
        public void Execute();
    }

    /// <summary>
    /// 打印命令
    /// </summary>
    public class PrintCommand : ICommand
    {
        public void Execute()
        {
            Console.WriteLine("Print");
        }
    }

    /// <summary>
    /// 调用者
    /// </summary>
    public class LogInvoker
    {
        /// <summary>
        /// 命令对象
        /// </summary>
        private ICommand Command;

        public LogInvoker(ICommand command)
        {
            this.Command = command;
        }

        public void SetCommand(ICommand command)
        {
            this.Command = command;
        }

        /// <summary>
        /// 执行命令
        /// </summary>
        public void Call()
        {
            //目的:在执行前后可增加任意内容
            Console.WriteLine("开始执行日志");
            this.Command.Execute();
            Console.WriteLine("执行完毕日志");
        }
    }

    /*
        调用方式:
        ICommand command = new PrintCommand();
        LogInvoker invoker = new LogInvoker(command);
        invoker.Call();
     */
}

4、责任链模式

场景:
一个请求需经过多重判断找到调用者。

定义:
避免请求发送者与多个请求处理者耦合在一起,于是将所有请求的处理者通过前一对象记住其下一个对象的引用而连成一条链。

目的:
将请求与多个调用者解耦,使请求者无需关注是谁处理了请求。

代码示例:

/// <summary>
/// 职责链
/// </summary>
public class ChainOfResponsibility
{
    /// <summary>
    /// 抽象处理者
    /// </summary>
    public abstract class IHander
    {
        /// <summary>
        /// 职责链的下一个处理者
        /// </summary>
        private IHander Next;

        /// <summary>
        /// 设置职责链的下一个处理者
        /// </summary>
        public void SetNext(IHander next) { 
            this.Next = next;
        }

        /// <summary>
        /// 执行下一个处理者
        /// </summary>
        /// <remarks>公共方法</remarks>
        public void DoNext(string type)
        {
            if(Next != null)
            {
                Next.Execute(type);
            }
        }

        /// <summary>
        /// 处理方法
        /// </summary>
        public abstract void Execute(string type);
    }

    /// <summary>
    /// 食品处理者
    /// </summary>
    /// <remarks>具体处理者</remarks>
    public class FoodHandler : IHander
    {
        public override void Execute(string type)
        {
            if (type.Equals("food"))
            {
                Console.WriteLine("处理食品");
                return;
            }
            //如果不处理,调用下一个处理对象
            DoNext(type);
        }
    }

    /// <summary>
    /// 饮品处理者
    /// </summary>
    /// <remarks>具体处理者</remarks>
    public class DrinkHandler : IHander
    {
        public override void Execute(string type)
        {
            if (type.Equals("drink"))
            {
                Console.WriteLine("处理饮品");
                return;
            }
            //如果不处理,调用下一个处理对象
            DoNext(type);
        }
    }

    /*
        调用方式:
        IHander foodHander = new FoodHandler();
        IHander drinkHander = new DrinkHandler();

        //组装职责链
        foodHander.SetNext(drinkHander);

        //提交请求
        foodHander.Execute("drink");
     */
}

5、状态模式

场景:
不同的状态不同的处理。

定义:
将判断逻辑提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。

目的:
将不同处理的判断逻辑解耦,满足单一职责原则。

缺点:
增加新的状态类需要修改那些负责状态转换的源码,并且修改某个状态类的行为也需要修改对应类的源码,违背了开闭原则。

代码示例:

/// <summary>
/// 状态模式
/// </summary>
public class State
{
    /// <summary>
    /// 抽象播放器状态类
    /// </summary>
    public abstract class PlayerState
    {
        /// <summary>
        /// 执行状态
        /// </summary>
        /// <param name="musicPlayer">音乐播放器</param>
        public abstract void Handle(MusicPlayer musicPlayer);

        /// <summary>
        /// 当前状态字符串
        /// </summary>
        /// <returns></returns>
        public abstract override string ToString();
    }

    /// <summary>
    /// 开始状态
    /// </summary>
    public class StartState : PlayerState
    {
        public override void Handle(MusicPlayer musicPlayer)
        {
            musicPlayer.SetState(this);
        }

        public override string ToString()
        {
            return "Start";
        }
    }

    /// <summary>
    /// 停止状态
    /// </summary>
    public class StopState : PlayerState
    {
        public override void Handle(MusicPlayer musicPlayer)
        {
            musicPlayer.SetState(this);
        }

        public override string ToString()
        {
            return "Stop";
        }
    }


    /// <summary>
    /// 音乐播放器
    /// </summary>
    /// <remarks>环境类</remarks>
    public class MusicPlayer
    {
        public PlayerState State { get; set; }

        public void SetState(PlayerState state)
        {
            this.State = state;
        }

        /// <summary>
        /// 打印当前状态
        /// </summary>
        public void PrintState()
        {
            Console.WriteLine(State.ToString());
        }
    }

    /*
        调用方式:
        MusicPlayer musicPlayer = new MusicPlayer();

        //执行Start状态
        StartState start = new StartState();
        start.Handle(musicPlayer);
        musicPlayer.PrintState();

        //执行Stop状态
        StopState stop = new StopState();
        stop.Handle(musicPlayer);
        musicPlayer.PrintState();
     */
}

6、观察者模式

场景:
一个对象的状态发生改变时,依赖于它的对象需得到通知。

定义:
多个对象间存在一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

目的:
降低了目标与观察者之间的耦合关系。

缺点:
目标与观察者之间的依赖关系并没有完全解除,而且有可能出现循环引用。

代码示例:

/// <summary>
/// 观察者模式
/// </summary>
public class Observer
{
    /// <summary>
    /// 观察者抽象
    /// </summary>
    public interface IObserver
    {
        /// <summary>
        /// 被通知的处理方法
        /// </summary>
        public void Handler(string state);
    }

    /// <summary>
    /// 观察者实现
    /// </summary>
    public class FoodObserver : IObserver
    {
        public void Handler(string state)
        {
            Console.WriteLine($"Food: {state}");
        }
    }

    /// <summary>
    /// 观察者实现
    /// </summary>
    public class DrinkObserver : IObserver
    {
        public void Handler(string state)
        {
            Console.WriteLine($"Drink: {state}");
        }
    }

    /// <summary>
    /// 目标对象
    /// </summary>
    /// <remarks>被观察的对象</remarks>
    public class Subject
    {
        List<IObserver> Observers = new List<IObserver> ();

        public string State { get; set; }

        /// <summary>
        /// 状态改变时通知所有观察者
        /// </summary>
        /// <param name="state"></param>
        public void SetState(string state)
        {
            this.State = state;
            Notify();
        }

        /// <summary>
        /// 添加观察者
        /// </summary>
        /// <param name="observer"></param>
        public void AddObserver(IObserver observer)
        {
            Observers.Add(observer);
        }

        /// <summary>
        /// 通知所有观察者
        /// </summary>
        public void Notify()
        {
            foreach (IObserver observer in Observers)
            {
                observer.Handler(State);
            }
        }
    }

    /*
        调用方式:
        Subject subject = new Subject();
        subject.AddObserver(new FoodObserver());
        subject.AddObserver(new DrinkObserver());

        subject.SetState("abc");
     */
}

7、中介者模式

场景:
一个对象发起请求,由中介者转发到多个目标实现。

定义:
定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。

目的:
对多个对象之间的交互解耦。

代码示例:

/// <summary>
/// 中介者模式
/// </summary>
public class Mediator
{
    /// <summary>
    /// 聊天室
    /// </summary>
    /// <remarks>中介者</remarks>
    public class ChatRoom
    {
        List<Client> Clients = new List<Client>();

        /// <summary>
        /// 注册客户端
        /// </summary>
        /// <param name="client"></param>
        public void RegisterClient(Client client)
        {
            this.Clients.Add(client);
        }

        /// <summary>
        /// 转发消息
        /// </summary>
        /// <param name="client">发送者</param>
        /// <param name="message">发送消息</param>
        public void Relay(Client client, string message)
        {
            foreach (Client clientItem in Clients)
            {
                //仅转发给其他客户端
                if (!clientItem.Equals(client))
                {
                    clientItem.Receive(message);
                }
            }
        }
    }

    /// <summary>
    /// 抽象客户端
    /// </summary>
    public abstract class Client
    {
        /// <summary>
        /// 聊天室
        /// </summary>
        protected ChatRoom ChatRoom { get; set; }

        public Client(ChatRoom chatRoom)
        {
            this.ChatRoom = chatRoom;
        }

        /// <summary>
        /// 接受消息
        /// </summary>
        public abstract void Receive(string message);

        /// <summary>
        /// 发送消息
        /// </summary>
        public abstract void Send();
    }

    /// <summary>
    /// App客户端
    /// </summary>
    public class AppClient : Client
    {
        public AppClient(ChatRoom chatRoom) : base(chatRoom)
        {
        }

        public override void Receive(string message)
        {
            Console.WriteLine($"App Receive: {message}");
        }

        public override void Send()
        {
            ChatRoom.Relay(this, "App Message");
        }
    }

    /// <summary>
    /// Web客户端
    /// </summary>
    public class WebClient : Client
    {
        public WebClient(ChatRoom chatRoom) : base(chatRoom)
        {
        }

        public override void Receive(string message)
        {
            Console.WriteLine($"Web Receive: {message}");
        }

        public override void Send()
        {
            ChatRoom.Relay(this, "Web Message");
        }
    }

    /*
        调用方式:
        ChatRoom room = new ChatRoom();
        var app = new AppClient(room);
        var web = new WebClient(room);
        room.RegisterClient(app);
        room.RegisterClient(web);

        app.Send();
        web.Send();
     */
}

8、迭代器模式

场景:
某个类型可被迭代,则应当封装一个迭代器来处理迭代。

定义:
提供一个对象来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。

目的:
封装对象的迭代行为。

代码示例:

/// <summary>
/// 迭代器模式
/// </summary>
public class Iterator
{
    /// <summary>
    /// 用户列表
    /// </summary>
    /// <remarks>实现IEnumerable</remarks>
    public class UserList : IEnumerable
    {
        public string User1 = "AAA";
        public string User2 = "BBB";
        public string User3 = "CCC";


        public IEnumerator GetEnumerator()
        {
            //在C#中实现迭代器非常简单
            //使用yield,每次迭代返回一个yield return的值
            yield return User1;
            yield return User2;
            yield return User3;

            //也可以用在循环里
            string[] users = new string[] { User1, User2, User3 };
            foreach (string user in users)
            {
                yield return user;
            }
        }
    }

    /*
        调用方式:
        UserList userList = new UserList();
        foreach (string user in userList)
        {
            Console.WriteLine(user);
        }
     */
}

9、访问者模式

场景:
对不同数据结构有不同操作。

定义:
将作用于某种数据结构中的各元素的操作分离出来封装成独立的类,使其在不改变数据结构的前提下可以添加作用于这些元素的新的操作,为数据结构中的每个元素提供多种访问方式。

目的:
将对数据的操作与数据结构进行分离。

代码示例:

/// <summary>
/// 访问者模式
/// </summary>
public class Visitor
{
    /// <summary>
    /// 商品抽象
    /// </summary>
    public interface ICommodity
    {
        public void Accept(ICommodityVistor visitor);
    }

    /// <summary>
    /// 食物
    /// </summary>
    /// <remarks>具体商品</remarks>
    public class Food : ICommodity
    {
        public void Accept(ICommodityVistor visitor)
        {
            visitor.Do(this);
        }

        public string GetFoodName()
        {
            return "Apple";
        }
    }

    /// <summary>
    /// 饮品
    /// </summary>
    /// <remarks>具体商品</remarks>
    public class Drink : ICommodity
    {
        public void Accept(ICommodityVistor visitor)
        {
            visitor.Do(this);
        }

        public string GetDrinkName()
        {
            return "Cola";
        }
    }

    /// <summary>
    /// 定义商品访问者
    /// </summary>
    public interface ICommodityVistor
    {
        /// <summary>
        /// 对食物的处理
        /// </summary>
        public void Do(Food food);

        /// <summary>
        /// 对饮品的处理
        /// </summary>
        public void Do(Drink drink);
    }

    /// <summary>
    /// 购买访问者
    /// </summary>
    public class BuyVistor : ICommodityVistor
    {
        public void Do(Food food)
        {
            Console.WriteLine($"Buy Food: {food.GetFoodName()}");
        }

        public void Do(Drink drink)
        {
            Console.WriteLine($"Buy Drink: {drink.GetDrinkName()}");
        }
    }

    /// <summary>
    /// 打印访问者
    /// </summary>
    public class PrintVistor : ICommodityVistor
    {
        public void Do(Food food)
        {
            Console.WriteLine($"Print Food: {food.GetFoodName()}");
        }

        public void Do(Drink drink)
        {
            Console.WriteLine($"Print Drink: {drink.GetDrinkName()}");
        }
    }

    /*
        调用方式:
        ICommodity food = new Food();
        food.Accept(new PrintVistor());
        food.Accept(new BuyVistor());

        ICommodity drink = new Drink();
        drink.Accept(new PrintVistor());
        drink.Accept(new BuyVistor());
     */
}

10、备忘录模式

场景:
记录一个状态,在需要时撤销当前状态,恢复到原先的状态。

定义:
保存一个对象的某个状态,以便在适当的时候恢复对象。

目的:
保存与恢复状态。

代码示例:

/// <summary>
/// 备忘录模式
/// </summary>
public class Memento
{
    /// <summary>
    /// 文本备忘录
    /// </summary>
    /// <remarks>存储发起人的任意状态值</remarks>
    public class TextMemento
    {
        public TextMemento(string text)
        {
            this.Text = text;
        }

        private string Text { get; set; }

        public void SetText(string text)
        {
            this.Text = text;
        }

        public string GetText()
        {
            return this.Text;
        }
    }

    /// <summary>
    /// 发起人
    /// </summary>
    /// <remarks>记录当前状态</remarks>
    public class Originator
    {
        /// <summary>
        /// 当前状态
        /// </summary>
        public string State { get; set; }

        public void SetState(string state)
        {
            this.State = state;
        }

        public string GetState()
        {
            return this.State;
        }

        /// <summary>
        /// 创建一个保存状态
        /// </summary>
        /// <returns></returns>
        public TextMemento CreateMemento()
        {
            return new TextMemento(State);
        }

        /// <summary>
        /// 返回一个保存状态
        /// </summary>
        public void RestoreMemento(TextMemento memento)
        {
            this.SetState(memento.GetText());
        }
    }

    /// <summary>
    /// 管理者
    /// </summary>
    /// <remarks>管理备忘录,但不能对备忘录内容修改</remarks>
    public class Caretaker
    {
        private TextMemento Memento { get; set; }

        public void SetMemento(TextMemento memento)
        {
            this.Memento = memento;
        }

        public TextMemento GetMemento()
        {
            return this.Memento;
        }
    }

    /*
        调用方式:
        Originator originator = new Originator();
        Caretaker caretaker = new Caretaker();

        originator.SetState("AAA");
        Console.WriteLine(originator.GetState());

        //保存一个状态
        caretaker.SetMemento(originator.CreateMemento());

        //赋予新状态
        originator.SetState("BBB");
        Console.WriteLine(originator.GetState());

        //恢复状态
        originator.RestoreMemento(caretaker.GetMemento());
        Console.WriteLine(originator.GetState());
     */
}

11、解释器模式

场景:
有些问题多次重复出现,而且有一定的相似性和规律性,可以将它们归纳成一种简单的语言(类似于编译器)。

定义:
给分析对象定义一个语言,并定义该语言的文法表示,再设计一个解析器来解释语言中的句子。

目的:
对于有一定的相似性和规律性的问题,定义灵活的处理方法。

代码示例:

/// <summary>
/// 解释器模式
/// </summary>
public class Interpreter
{
    //多元加法解释器

    /// <summary>
    /// 表达式抽象
    /// </summary>
    public interface Expression
    {
        /// <summary>
        /// 解释方法
        /// </summary>
        /// <returns>解释后需返回的对象(本例中为计算后的值)</returns>
        public int Interpret(string value);
    }

    /// <summary>
    /// 值表达式
    /// </summary>
    /// <remarks>终结符表达式(即不调用其他表达式的表达式)</remarks>
    public class ValueExpression : Expression
    {
        /// <summary>
        /// 解释值表达式
        /// </summary>
        public int Interpret(string value)
        {
            return Convert.ToInt32(value);
        }
    }

    /// <summary>
    /// 加法表达式
    /// </summary>
    /// <remarks>非终结符表达式(即需调用其他表达式的表达式)</remarks>
    public class AddExpression : Expression
    {
        private Expression Expression;

        public AddExpression(Expression expression)
        {
            this.Expression = expression;
        }

        /// <summary>
        /// 解释加法表达式
        /// </summary>
        public int Interpret(string value)
        {
            var values = value.Split('+');

            int sum = 0;
            foreach (var val in values)
            {
                sum += Expression.Interpret(val);
            }

            return sum;
        }
    }

    /// <summary>
    /// 计算解释器
    /// </summary>
    public class CalcInterpreter
    {
        private Expression Expression;

        public CalcInterpreter()
        {
            var valueExpression = new ValueExpression();
            Expression = new AddExpression(valueExpression);
        }

        public int Execute(string expressionStr)
        {
            return Expression.Interpret(expressionStr);
        }
    }

    /*
        调用方式:
        var calc = new CalcInterpreter();
        calc.Execute("1+2+3+4+5");
     */
}

配套源码:
C# .Net设计模式与代码实现

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值