初尝Mediator 模式

2010年5月4日 邵 明博 没有评论

在日常生活中,我们经常会遇到多个事物相互之间都有联系的例子。例如:聊天室。

在软件构建过程中,经常会出现多个对象互相关联交互的情况,对象之间常常会维持一种复杂的引用关系,如果遇到一些需求的更改,这种直接的引用关系将面临不断的变化。在这种情况下,我们可使用一个“中介对象”来管理对象间的关联关系,避免相互交互的对象之间的紧耦合引用关系,从而更好地抵御变化。

意图

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式的相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

结构图

mediator 结构图

在这里,我们模拟一个聊天室的程序,用户既可以对特定的对象进行发送消息,也可以向所有人say hello。我们用一个mediator 对象进行管理他们之间的联系。值得指出的是,代码中,仍有值得抽象的接口。

代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Mediator
{
    class Program
    {
        static void Main(string[] args)
        {
            ChatRoom cr = new ChatRoom();
            Participator p = new Participator("Shao mingbo",cr);
            Participator p2 = new Participator("YW",cr);
            Participator p3 = new Participator("ZZ",cr);
            Participator p4 = new Participator("Xiao Di",cr);
            //Say Hello to The One
            p.Send(p2,"Hello");
            Console.WriteLine("--------------");
            // Say Hi To All
            p4.Send("Hi");
        }
    }
    class Participator {
        private string _name;
        private ChatRoom cr;

        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
        public Participator(string name,ChatRoom cr) {
            this._name = name;
            this.cr = cr;
            cr.RegistParticipator(this);
        }
        public void Receive(string from,string msg) {
            if(cr!=null)
                Console.WriteLine("{0} 收到来自 {1}的一则消息: {2}", this.Name, from, msg);
            else
                Console.WriteLine("{0} 未曾在聊天室内注册!", this._name);
        }
        public void Send(Participator p,string msg) {
            if (cr != null) {
                cr.RegistParticipator(this);
                cr.Notify(this.Name,p, msg);
            }
            else
                Console.WriteLine("{0} 未曾在聊天室内注册!",this._name);

        }

        public void Send(string msg) {
            this.Send(null,msg);
        }
    }
    class ChatRoom {
        private Dictionary roomMate = new Dictionary();
        public void RegistParticipator(Participator p) {
            if (!roomMate.ContainsKey(p.Name))
                roomMate.Add(p.Name,p);
        }
        public void Notify(string from,Participator p, string msg) {
            if (p != null)
            {
                p.Receive(from, msg);
            }
            else {
                foreach (var receiver in roomMate) {
                    if (receiver.Key != from) {
                        Participator r = receiver.Value;
                        r.Receive(from,msg);
                    }
                }
            }
        }
    }

}

运行结果:

mediator 运行结果

初尝Interpretor 模式

2010年5月1日 邵 明博 没有评论

这个模式,一般用的很少。通常一个解释器,都会有专门的对象或者更底层(更高效)的工具来解决相应的问题。但有通常,就会有特殊的情况。当我们需要剖析某个具有结构性的对象,而这个对象并没有那么庞大时,就可以采用Interpretor 模式。

意图:
给定一个语言,定义它的文法的一种表示,并定义一种解释器,这个解释器使用该表示来解释语言中的句子。

结构图:

Interpretor 模式结构

这个模式让我纠结了几天。原因不在理解这个模式本身,而是老师在课堂举的一个解释器的例子(将汉语数字转换成阿拉伯数字。比如:九千一百二十万六千三百二十一 –>91206321 )这样的计算处理,不用设计模式,也能实现。但,使用了设计模式,可以在代码复用以及一些小型的语法处理问题得到很好的效果。当然最后还是实现了,但这充分说明,自己实现一个解释器,并不容易。

在写代码的过程中,我有尝试从最高位向低位来转换,但发现后期扩展就受到了这个方向的限制。所以,我得出了一个不完全的总结,就是在使用Interpretor 模式的过程中,应该先从最小的单位单元(个位)进行,然后依次递增。

代码

using System;
using System.Collections;
using System.Collections.Generic;

namespace DesignPattern
{
    class Program
    {
        static void Main(string[] args)
        {
            //初始化翻译数据...
            string[] numbers = { "九千一百二十万",
                                   "九千一百二十万六千三百二十一",
                                   "六千",
                                   "六千零一",
                                   "六千零一十",
                                   "六千一",
                                   "六千一百",
                                   "六千二百一十",
                                   "六千二百一",
                                   "六千二百零一",
                                   "六千零二十一",
                                   "六千三百二十一",
                                   "一百",
                                   "一百一",
                                   "一百一十",
                                   "一百零一",
                                   "一百一十一",
                                   "二十一",
                                   "二十",
                                   "八" };
            ArrayList contextList = new ArrayList();
            for (int i = 0; i < numbers.Length; i++)
            {
                contextList.Add(new Context(numbers[i]));
            }
            //初始化编译器...
            OneExpression one = new OneExpression();
            TenExpression ten = new TenExpression();
            HundredExpression hun = new HundredExpression();
            ThousandExpression thou = new ThousandExpression();
            TenThousandExpression tenThou = new TenThousandExpression();

            ArrayList list = new ArrayList();
            list.Add(one);
            list.Add(ten);
            list.Add(hun);
            list.Add(thou);
            list.Add(tenThou);

            //开始翻译工作啦...
            foreach (Context c in contextList)
            {
                Console.Write("Input: {0}\t", c.Input);
                foreach (Expression ex in list)
                    ex.Interprete(c);
                Console.WriteLine("Output: {0}", c.Output);

            }

        }
    }
    class Context {
        private string _input;

        public string Input
        {
            get { return _input; }
            set { _input = value; }
        }
        private long _output;

        public long Output
        {
            get { return _output; }
            set { _output = value; }
        }

        public Context(string input) {
            this._input = input;
        }
    }

    abstract class Expression
    {
        protected Dictionary charDic = new Dictionary();
        protected Stack mutiplier = new Stack();
        protected int _data;
        public Expression()
        {
            charDic.Add("一", 1);
            charDic.Add("二", 2); charDic.Add("两", 2);
            charDic.Add("三", 3); charDic.Add("四", 4);
            charDic.Add("五", 5); charDic.Add("六", 6);
            charDic.Add("七", 7); charDic.Add("八", 8);
            charDic.Add("九", 9);
        }
        public abstract void Interprete(Context context);
    }

    class OneExpression : Expression
    {
        public override void Interprete(Context context)
        {
            //throw new NotImplementedException();
            if (context.Input.Length <= 0) return;
            if (context.Input.Length == 1)
            {
                if (charDic.ContainsKey(context.Input))
                {
                    this._data = charDic[context.Input];
                    context.Output += this._data;
                    context.Input = String.Empty;
                    return;
                }
            }
            string lastWord = context.Input.Substring(context.Input.Length - 1);
            string preWord = context.Input.Substring(0, context.Input.Length - 1);
            if (context.Input.Length == 2)
            {
                if (charDic.ContainsKey(lastWord))
                {
                    this._data = charDic[lastWord];
                    context.Output += this._data;
                    context.Input = context.Input.Substring(0, context.Input.Length - 1);
                }
            }
            if (context.Input.Length > 2)
            {
                if (charDic.ContainsKey(lastWord))
                {
                    if (preWord.EndsWith("十") || preWord.EndsWith("零"))
                    {
                        this._data = charDic[lastWord];
                        context.Output += this._data;
                        context.Input = context.Input.Substring(0, context.Input.Length - 2);
                    }
                }
            }
        }
    }
    class TenExpression : Expression
    {
        public override void Interprete(Context context)
        {
            if (context.Input.Length <= 0) return;
            if (context.Input.Length == 1)
            {
                if (this.charDic.ContainsKey(context.Input))
                {
                    context.Output += charDic[context.Input] * 10;
                }
                if (context.Input.Equals("十"))
                {
                    context.Output += 10;
                }
                context.Input = String.Empty;
                return;
            }
            string lastWord = context.Input.Substring(context.Input.Length - 1);
            string preWord = context.Input.Substring(0, context.Input.Length - 1);
            if (context.Input.Length == 2)
            {
                if (lastWord.Equals("十"))
                {
                    if (this.charDic.ContainsKey(preWord))
                    {
                        context.Output += this.charDic[preWord] * 10;
                        context.Input = String.Empty;
                    }
                }
            }

            if (context.Input.Length > 2)
            {
                if (lastWord.Equals("十"))
                {
                    lastWord = preWord.Substring(preWord.Length - 1);
                    preWord = preWord.Substring(0, preWord.Length - 1);
                }
                if (this.charDic.ContainsKey(lastWord))
                {
                    if (preWord.EndsWith("百") || preWord.EndsWith("零"))
                    {
                        this._data = this.charDic[lastWord];
                        context.Output += this._data * 10;
                        context.Input = preWord.Substring(0, preWord.Length - 1);
                    }
                }
            }
        }
    }
    class HundredExpression : Expression
    {
        public override void Interprete(Context context)
        {
            if (context.Input.Length == 0) return;
            if (context.Input.Length == 1)
            {
                if (this.charDic.ContainsKey(context.Input))
                {
                    this._data = this.charDic[context.Input];
                    context.Output += this._data * 100;
                }
                context.Input = String.Empty;
                return;
            }
            string lastWord = context.Input.Substring(context.Input.Length - 1);
            string preWord = context.Input.Substring(0, context.Input.Length - 1);
            if (context.Input.Length == 2)
            {
                if (lastWord.Equals("百"))
                {
                    if (this.charDic.ContainsKey(preWord))
                    {
                        context.Output += this.charDic[preWord] * 100;
                        context.Input = String.Empty;
                    }
                }
            }
            if (context.Input.Length > 2)
            {
                if (lastWord.Equals("百"))
                {
                    lastWord = preWord.Substring(preWord.Length - 1);
                    preWord = preWord.Substring(0, preWord.Length - 1);
                }
                if (this.charDic.ContainsKey(lastWord))
                {
                    if (preWord.EndsWith("千") || preWord.EndsWith("零"))
                    {
                        this._data = this.charDic[lastWord];
                        context.Output += this._data * 100;
                        context.Input = preWord.Substring(0, preWord.Length - 1);
                    }
                }
            }
        }
    }
    class ThousandExpression : Expression
    {
        public override void Interprete(Context context)
        {
            if (context.Input.Length <= 0) return;
            if (context.Input.Length == 1)
            {
                if (this.charDic.ContainsKey(context.Input))
                {
                    this._data = this.charDic[context.Input];
                    context.Output += this._data * 1000;
                }
                context.Input = String.Empty;
                return;
            }
            string lastWord = context.Input.Substring(context.Input.Length - 1);
            string preWord = context.Input.Substring(0, context.Input.Length - 1);
            if (context.Input.Length == 2)
            {
                if (lastWord.Equals("千"))
                {
                    if (this.charDic.ContainsKey(preWord))
                    {
                        context.Output += this.charDic[preWord] * 1000;
                        context.Input = String.Empty;
                    }
                }
            }
            if (context.Input.Length > 2)
            {
                if (lastWord.Equals("千"))
                {
                    lastWord = preWord.Substring(preWord.Length - 1);
                    preWord = preWord.Substring(0, preWord.Length - 1);
                }
                if (this.charDic.ContainsKey(lastWord))
                {
                    if (preWord.EndsWith("万") || preWord.EndsWith("零"))
                    {
                        this._data = this.charDic[lastWord];
                        context.Output += this._data * 1000;
                        context.Input = preWord.Substring(0, preWord.Length - 1);
                    }
                }
            }
        }
    }
    class TenThousandExpression : Expression
    {
        public override void Interprete(Context context)
        {
            if (context.Input.Length <= 0) return;
            if (context.Input.EndsWith("万"))
            {
                context.Input = context.Input.Substring(0, context.Input.Length - 1);
            }
            long temp = context.Output;
            context.Output = 0;
            OneExpression one = new OneExpression();
            TenExpression ten = new TenExpression();
            HundredExpression hun = new HundredExpression();
            ThousandExpression thou = new ThousandExpression();
            ArrayList list = new ArrayList();
            list.Add(one);
            list.Add(ten);
            list.Add(hun);
            list.Add(thou);
            foreach (Expression ex in list)
            {
                ex.Interprete(context);
            }
            context.Output *= 10000;
            context.Output += temp;

        }
    }
}

运行结果

Interpretor 运行结果

这里是测试程序,如果有bug,请联系我哟。点击下载:Interpretor 演示代码 (36)

初尝Command 模式

2010年4月28日 邵 明博 没有评论

在软件系统中,“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合,比如要对行为进行“记录、撤销/重做、事务”等处理,这种无法抵御变化的紧耦合是不合适的。在这种情况下,如何将“行为请求者”与“行为实现者”解耦?将一组行为抽象为对象,可以实现二者之间的松耦合。这就是本文要说的Command模式。

意图

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤消的操作。

结构图

Command结构图 初尝Command 模式

代码:

using System;
using System.Collections.Generic;

namespace Command
{
    class Program
    {
        static void Main(string[] args)
        {
            //只有计算能力
            Caculator c = new Caculator();
            //实现Undo
            CaculatorCommand cc = new CaculatorCommand(c);
            //添加了Undo的堆栈
            CaculatorInvoker cInvoker = new CaculatorInvoker(cc);
            cInvoker.Caculate('+',2);
            cInvoker.Caculate('*', 7);
            cInvoker.Caculate('-', 3);
            cInvoker.Caculate('/', 4);
            cInvoker.UnCaculate();
            cInvoker.UnCaculate();
            cInvoker.UnCaculate();
        }
    }

    interface Command {
        void SetParam(object[] objects);
        void Excute();
        void UnExcute();
    }

    class Caculator {
        private double total = 0;

        public void Compute(char @operator,double param) {
            switch (@operator) {
                case '+': total += param;  break;
                case '-': total -= param; break;
                case '*': total *= param; break;
                case '/': total /= param; break;
                default: throw new ArgumentException();
            }
            Console.WriteLine("Current value = {0,3} (following {1} {2})",total,@operator,param);
        }
    }

    class CaculatorCommand : Command {
        private Caculator caculator;
        private char @operator;
        private double param;

        public CaculatorCommand(Caculator c) {
            this.caculator = c;
        }
        public void SetParam(object[] objects) {
            this.@operator = (char)objects[0];
            this.param = (double)objects[1];
        }
        public void Excute() {
            caculator.Compute(@operator,param);
        }
        public void UnExcute() {
            caculator.Compute(this.Undo(@operator),param);
        }
        private char Undo(char @op) {
            switch (@op) {
                case '+': return '-';
                case '-': return '+';
                case '*': return '/';
                case '/':return '*';
                default: throw new ArgumentException();
            }
        }
    }

    class CaculatorInvoker {
        private Command cmd;
        private Stack paramsStack = new Stack();

        public CaculatorInvoker(Command cmd) {
            this.cmd = cmd;
        }

        public void Caculate(char @operator,double param) {
            object[] paras = new object[] { @operator,param};
            cmd.SetParam(paras);
            cmd.Excute();
            paramsStack.Push(paras);
        }

        public void UnCaculate() {
            if (paramsStack.Count < 0) return;
            object[] paras = paramsStack.Pop();
            cmd.SetParam(paras);
            cmd.UnExcute();
        }
    }
}


运行截图:

Command运行结果 初尝Command 模式

话说回来,如果只看Main 函数,感觉像用的是Decorator 模式。从这一点不难发现,模式之间由于总体原则的类似,导致他们长得都很相像。

初尝Template 模式

2010年4月27日 邵 明博 没有评论

模板模式,实际上是所有模式中最为常见的几个模式之一,而且很多人可能使用过模版方法模式而没有意识到自己已经使用了这个模式。模版方法模式是基于继承的代码复用的基本技术,模版方法模式的结构和用法也是面向对象设计的核心。

概述

变化一直以来都是软件设计的永恒话题,在XP编程中提倡拥抱变化,积极应对。如何更好的去抓住变化点,应对变化?如何更好的提高代码复用?通过学习Template Method模式,您应该有一个新的认识。

意图

定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

结构图

template模式 初尝Template 模式

由于这个模式,过于常见,这里也不必给出相应代码了。