设计模式之行为模式

行为模式是对不同的对象之间,划分其责任和算法。

 

分类:类结构模式或对象结构模式

包含下列模式:

1)不变模式

2)策略模式

3)模板方法模式

4)观察者模式

5)迭代子模式

6)责任链模式

7)命令模式

8)备忘录模式

9)状态模式

10)访问者模式

11)解释器模式

12)调停者模式

 

 

 

一、不变模式

例子:Java里String,Integer, Float等各种封装类

分为:

1)弱不变模式: 子类可能有变化。

2)强不变模式: 子类业务变化或根本不能有子类。

注意:

1)不变模式不是无状态,它可以有状态,只不过状态不变而已。

2)不同于只读属性。例如年龄,即使设置了只读属性,随着时间的变化,其年龄属性也发生变化。

使用方法:

直接在构造的时候,确定状态值,并不允许以后再修改状态。

 

二、策略模式

例子:以前做的台球算账程序,图书折扣,诸葛亮的锦囊妙计(3个锦囊,3个计策)

目的是封装一组算法,每一个算法是一个具体的策略类。

使用的时候由客户端来决定具体使用哪一个策略类。

 

三、模板方法模式

例子:好莱坞原则,西天取经八十一难(这81磨难是设计好不能少的,唐僧是具体模板,经历了西游记的81难,换成我去取经也是要经历81难的,第一难,第二难。。。。第81难)

准备一个抽象类,将顶级的逻辑完成,然后声明一些抽象方法来迫使子类来实现其余的逻辑。(这些抽象方法已被抽象类的顶级逻辑所调用)

不同的子类以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。

跟建造模式很像,不过建造模式多了一个director角色,顶级逻辑都放在direcotr角色中。

  1. 建造者是使用组合方式实现不同的表示,而模板方法使用的是继承的方式。组合优于继承。
  2. 建造者抽象的是构建过程,而模板方法提取的是公共实现。

 

四、观察者模式

例子:发布-订阅,awt的Listener。

校色有两类,一个是主题,一个是观察者对象,它们是1:N的关系。

当主题的状态发生变化时,可以通知所有的观察者对象。 (调用观察者对象类似Update()的方法)

 

五、迭代子模式

目的:该模式将迭代逻辑(正序遍历,反序遍历,增加,删除)与聚集本身分开。(聚集是采用vector还是list,都不影响迭代)。

该模式可采用内部类的方式,限制其他类对聚集类索引的访问。(只对迭代类公开)

 

六、责任链模式

例子:传花击鼓, AWT事件处理,java城堡竞赛

很对对象由每一个对象对其下家的引用而连接起来形成一个链条。

关键点:基类有类似的三个函数

1)是否满足

2)满足执行的一些action

3)取得下家(不满足时)

    public class Entry
    {
        public static void MainProc()
        {
            var player = new Zhangsan(new Lisi(new Wangwu(null)));
            player.Handle("李");
        }
    }

    public interface IPlayer
    {
        bool IsMeet(string lastName);
        IPlayer Next { get; set; }
        bool Handle(string lastName);
    }

    public abstract class Player : IPlayer
    {
        abstract public bool IsMeet(string lastName);
        abstract public void Action();

        public Player(IPlayer next)
        {
            Next = next;
        }

        public IPlayer Next { get; set; }
        public bool Handle(string lastName)
        {
            if (IsMeet(lastName))
            {
                Action();
                return true;
            }
            else
            {
                if (Next == null)
                    return false;
                else
                    return Next.Handle(lastName);
            }
        }
    }

    public class Zhangsan: Player
    {
        public Zhangsan(IPlayer next) : base(next) { }
        public override bool IsMeet(string lastName)
        {
            return lastName.IndexOf("张") == 0;
        }

        public override void Action()
        {
            Console.WriteLine("I am 张三");
        }
    }

    public class Lisi : Player
    {
        public Lisi(IPlayer next) : base(next) { }
        public override bool IsMeet(string lastName)
        {
            return lastName.IndexOf("李") == 0;
        }

        public override void Action()
        {
            Console.WriteLine("I am 李四");
        }
    }

    public class Wangwu : Player
    {
        public Wangwu(IPlayer next) : base(next) { }
        public override bool IsMeet(string lastName)
        {
            return lastName.IndexOf("王") == 0;
        }

        public override void Action()
        {
            Console.WriteLine("I am 王五");
        }
    }

七、命令模式

重点的对象是命令(抽象对象和具体对象)

简单来说,这个模式是在请求者和接受者之间建立一个command角色,请求者只关心Command, 与接受者解耦。类似于c的callbcack。

例子:太上老君请猴王上天。 请求者太上老君,接受者猴王,命令是执行的圣旨。

 

再例如Ken用遥控器操纵电视开机,关机,换台:

电视是接受者,有开机,关机,换台三个函数。

实体Command有3个类,调用Execute时,分别调用开机,关机,换台这三个函数。

遥控器是Invoker。Ken是客户端。

    public class CommandClient
    {
        public void Action()
        {
            var receiver = new Receiver("Monkey King");
            var cmd = new ConCommand(receiver);
            var invoker = new Invoker(cmd);
            invoker.Name = "Tai Bai Jin Xing";
            invoker.Action();
        }
    }


    public class Receiver
    {
        private string Name;

        public Receiver(string name)
        {
            this.Name = name;
        }

        public void Fly()
        {
            Console.WriteLine(Name + ": fly to sky.");
        }
    }

    public class ConCommand : ICommand
    {
        private Receiver receiver;

        public ConCommand(Receiver receiver)
        {
            // TODO: Complete member initialization
            this.receiver = receiver;
        }

        void ICommand.Execute()
        {
            receiver.Fly();
        }
    }

    public class Invoker
    {
        private ICommand Cmd;

        public Invoker(ICommand cmd)
        {
            // TODO: Complete member initialization
            this.Cmd = cmd;
        }

        public void Action()
        {
            if(Cmd != null)
            {
                Cmd.Execute();
            }
        }

    }

 

上帝造万物。 抽象命令角色只需要一个借口函数execute(), 具体命令角色:造天command, 造地command, 造人command等。

常会用于回调,undo/redo等场合。

 

八,备忘录模式

角色: Originator角色,Memento角色,和TakeCare角色。

为了方便理解:

orginator可以理解为manager,使用数据者;

Memento理解为dataModule,

careTaker稍微难理解,就是负责引用dataModule的对象

 public class Entry
    {
        public static void MainProcess()
        {
            // orginator可以理解为manager或View,使用数据者
            var orginator = new Originator();
            // Status就是数据
            orginator.Status = "On";

            var careTaker = new CareTaker();
            
            // Memento可以理解为dataModule,orginator用CreateMemento方法将dataModule创建出来,
            // 并当做参数传给careTaker.SaveMemento里
            // careTaker这里只起到暂时引用Memento(dataModule)的作用,
            // 实际用途中是否可以增加数据序列化的处理??
            careTaker.SaveMemento(orginator.CreateMemento()); // very important

            // 编辑中
            orginator.Status = "Off";

            // 放弃编辑,careTaker.RetrieveMemento()将dataModule取出,并当做参数传递给orginator.RestoreMemento()用于restore
            orginator.RestoreMemento(careTaker.RetrieveMemento());
        }
    }

    public class Originator
    {
        public string Status { get; set; }

        public Memento CreateMemento()
        {
            return new Memento(Status);
        }

        public void RestoreMemento(Memento memento)
        {
            Status = memento.Status;
        }
    }

    public class Memento
    {
        public string Status { get; set; }

        public Memento(string Status)
        {
            this.Status = Status;
        }
    }

    public class CareTaker
    {
        public Memento memento { get; set; }
        public void SaveMemento(Memento memento)
        {
            this.memento = memento;
        }

        public Memento RetrieveMemento()
        {
            return memento;
        }
    }

 

 

九, 状态模式

状态抽象类和具体状态类(多个),Context类。

需要考虑由谁负责更改状态,可以是Context类或者是一个具体的状态类。推荐用具体的状态类来切换状态。

重点且接受不了的是:状态类接口定义的行为,例如EmptyStatus::AddPeopel() 

近期工作涉及到controller的状态模式,模式是按照以下方式运行:

  • 所有引发状态改变都是调用Init(Action_Name),状态从InitState开始。
  • State有两个函数,一个是NextTransaction,根据Action_Name确定下一个行为是什么?
  • 另一个是NextState,根据行为后的结果,确定下一个状态是什么。

举例:IdelState->InitState->ConnectedState->RemoteModeState(检测是否支持rmc)->CrcState->UncommittedState->IdelState

 

十,访问者模式

一个有争议的模式,慎用。该模式是将大量的逻辑写入到visitor里(很多重载函数),而不是通过多态分散到node里。

对象: Vistor对象,Node对象。

实现方式有点像足球来回倒脚。

  • Vistor写一堆Visit重载函数。 因为重载函数是编译器已经定义好的,所以是静态派分而非动态。
  • 遍历所有的Node,每个Node调用node.Accept(visitor)。=》球在node那儿
  • 在node.Accept中,调用visitor的Visit重载函数 =》球在Visitor那里
  • Vist的重载函数最终会调用实际需要的node函数 =》球又回到了node那里

注意

Node的类型数量最好固定才建议使用该模式,否则重载函数就要相应的增加。

另外如果重载函数太多,不建议使用重载函数,直接通过函数名区分,例如VisitNodeA,VisitNodeB,VisitNodeC...

最好Visitor也是多个的时候使用该模式,例如一个visitor类访问所有的nodes用于计算,另外一个visitor类访问所有的nodes用于打印。

   public class Entry
    {
        public static void MainProc()
        {
            var nodes = new List<INode>();
            nodes.Add(new NodeA());
            nodes.Add(new NodeB());
            nodes.Add(new NodeA());
            nodes.Add(new NodeB());
            nodes.Add(new NodeB());
            nodes.Add(new NodeA());

            var visitor = new Visitor();
            foreach (var node in nodes)
            {
                node.Accept(visitor);
            }
        }
    }

    public class Visitor
    {
        public void Visit(NodeA nodeA)
        {
 	        nodeA.PrintA();
        }

        public void Visit(NodeB nodeB)
        {
 	        nodeB.PrintB();
        }
    }

    
    public interface INode
    {
        void Accept(Visitor visitor);
    }

    public class NodeA : INode
    {
        public void Accept(Visitor visitor)
        {
 	        visitor.Visit(this);
        }

        public void PrintA()
        {
            Console.WriteLine("Print NodeA");
        }
    }

    public class NodeB : INode
    {
        public void Accept(Visitor visitor)
        {
 	        visitor.Visit(this);
        }

        public void PrintB()
        {
            Console.WriteLine("Print NodeB");
        }
    }

 

十一,解释器模式

用于解释编程"语言" (AST)

每个terminal都有一个interpret()方法。

"And" 这种非termina的Express有leftExpress和rightExpress。 

在文章中,并没有看到AST的作用,也没用看到处理terminal和非terminal有什么不同。

例子中"var express = new AND(new Constant(true), new StringBool("true"));" 这不可能出现在"语言"中。

语言写法应类似于: var express = true && "true" ,要转化成上面的写法就需要AST(语法树)

    public class Entry
    {
        public static void MainProc()
        {
            var express = new AND(new Constant(true), new StringBool("true"));
            var ret = express.interfect();
            Console.WriteLine(ret.ToString());
        }
    }
    public interface IInterpret
    {
        bool interfect();
    }

    public class Constant : IInterpret
    {
        private bool Value;
        public Constant(bool value)
        {
            Value = value;
        }

        public bool interfect()
        {
            return Value;
        }
    }

    public class StringBool : IInterpret
    {
        private string Value;
        public StringBool(string value)
        {
            Value = value;
        }

        public bool interfect()
        {
            return string.Equals("true", Value.ToLower().Trim());
        }
    }

    public class AND : IInterpret
    {
        IInterpret Left;
        IInterpret Right;
        public AND(IInterpret left, IInterpret right)
        {
            Left = left;
            Right = right;
        }

        public bool interfect()
        {
            return Left.interfect() && Right.interfect();
        }
    }

 

十二,调停者模式

角色:调停者Mediator, 各个同事的角色Colleage

慎用该模式,使用该模式,一般说明系统设计较差。

很多Colleage之间的关系混乱,相互引用太多,才考虑使用该模式。

该模式切断Colleage之间的联系,让所有的Colleage只和Mediator交互。

跟门面模式不同的是,该模式交互是双向的。

   public class Entry
    {
        public static void MainProc()
        {
            var mediator = new Mediator();
            var colleage1 = new Colleage1(mediator);
            var colleage2 = new Colleage2(mediator);
            mediator.Colleage1Inst = colleage1;
            mediator.Colleage2Inst = colleage2;
            colleage2.Change2();
        }
    }

    public class Colleage1
    {
        private Mediator MediatorInst { get; set; }

        public Colleage1(Mediator mediator)
        {
            MediatorInst = mediator;
        }

        public void Change1()
        {
            MediatorInst.Change(this);
        }
        public void Action1()
        {
            Console.WriteLine("Action1 for changing.");
        }
    }

    public class Colleage2
    {
        private Mediator MediatorInst { get; set; }
        public Colleage2(Mediator mediator)
        {
            MediatorInst = mediator;
        }
        public void Change2()
        {
            MediatorInst.Change(this);
        }
        public void Action2()
        {
            Console.WriteLine("Action2 for changing.");
        }

    }

    public class Mediator
    {
        public Colleage1 Colleage1Inst { get; set; }
        public Colleage2 Colleage2Inst { get; set; }

        public void Change(Colleage1 colleage1)
        {
            Colleage2Inst.Action2();
        }
        public void Change(Colleage2 colleage2)
        {
            Colleage1Inst.Action1();
        }
    }

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值