关于客户端编写的问题
最近在敲大话设计模式中的C#代码.我是在看UML图去敲代码的.由于UML图中没有画出客户端的图.
导致写客户端的代码时,很是费力.不清楚该怎么写.没有一点的章法.总是蒙几句.最后运行出来了,感觉就是
对的,也不知道自己是怎么写出来的.让我从头写一次.和上次的感觉还是一样的.我仔细分析了一下.关于为什么不会写客户端.我感觉这不是一个单纯的编码问题.也不是你对语言的理解不深刻.
其实是你对程序的过程理解不深刻,对各个类的职能不理解.对面向对象不理解.
我这里只讨论控制台程序.
比如一个程序你不会写客户端,其实你就是不知道客户是如何调用它的.
这个面向对象的技术有很大关系.你的程序已近都把你将要用的类,功能编写完毕了.那么客户端是什么呢?
其实就是你如何去实例化这些类,那些类该实例化,在那个时候实例化.让他们变成能工作的具体对象.然后
是如何利用这些对象的方法.也就是功能.我们往往感到困惑的地方就是如何实例化这些类.很多的时候客户端要体现OO的多态特征.要用父类去实
例化子类,如果你直接运用了子类实例化自己.其实反映出来的就是你对多态的不理解.为什么要用多态,
个人理解一是:为了程序的灵活性,父类可以实例化很多的子类,不用一个一个的判断我要用到那个子类,
然后再去实例化,减轻了客户端的负担.二是: 为了方便调用,调用的时候,我客户端不需要知道你到底是那个
子类的方法,只需要调用父类的同样的方法,就能控制子类.能快速高效的把客户端写好,证明这个程序的思路你就已近理解了.下面举一个例子来说明一下:
就拿设计模式中的<适配器模式>来说(c#)
首先你先设计出各个类.就好像是你要做饭先把各个料备好.
1: //抽象父类球员,每个人都有进攻,防守方法
2: abstract class Player3: {4: protected string name;5: public Player(string name)6: {7: this.name = name;
8: }9: public abstract void Attack();10: public abstract void Defense();11: }
1: //具体球员前锋类
2: class Forwards : Player
3: {4: public Forwards(string name)5: : base(name)
6: { }7:8: public override void Attack()9: {10: Console.WriteLine("前锋{0} 进攻", name);
11: }12: public override void Defense()13: {14: Console.WriteLine("前锋" + name + "防守");15: }16:17: }
1: //具体球员后卫类,继承player
2: class Guard : Player
3: {4: public Guard(string name)5: : base(name)
6: { }7: public override void Attack()8: {9: Console.WriteLine("后卫{0} 进攻 ", name);
10: }11: public override void Defense()12: {13: Console.WriteLine("后卫" + name + "防守");14: }15: }
1: //外籍球员类,注意没有继承player,说明他直接和其他队员不能沟通
2: class ForeignCenter
3: {4: private string name;5: public string Name6: {7: get { return name; }8: set { name = value; }9: }10: public void jingong()11: {12: Console.WriteLine("外籍中锋{0}进攻 ", name);
13: }14: public void fangshou()15: {16: Console.WriteLine("外籍中锋{0}防守 " ,name);
17: }18: }
1: //外籍球员的翻译人员.继承player,说明是他和其他球员沟通
2: class Translator : Player
3: {4: private ForeignCenter fc = new ForeignCenter();5:6: public Translator(string name)7: : base(name)
8: {9: fc.Name = name;10: }11: public override void Attack()12: {13: fc.jingong();14: }15: public override void Defense()16: {17: fc.fangshou();18: }19: }
所以的料都备好以后.开始做饭:也就是写客户端.
首先要打球,我们就要有队员.
(1)实例化队员,队员就包括前锋,后卫,中锋都要有Player f = new Forwards("巴蒂尔");
Player g = new Guard("阿尔斯通");这里很明显的一点就是用父类去实例化子类的构造方法.能让人很好的理解.这些人都是球员.体现了多态.这样做.当有特殊条件的时候,就可以用特殊条件实例化(见试验二).方便吧.
(2)对于中锋因为他是一个外籍球员,我们当然不能和其他人一样对待.注意刚才我们写类的时候,中锋没有继承player,而是翻译
说明我们要实例化的时候,就是给外籍中锋配一个翻译.Player ym = new Translator("姚明");
这个翻译让姚明干什么,姚明就去干什么(这个本人感觉很像是代理模式).(3)然后就是下锅了,谁有什么本事就使出来.能发甜的发甜,发辣的发辣.
也就是调用他们的方法.
1: f.Attack();2: f.Defense();3: g.Attack();4: g.Defense();5: ym.Attack();6: ym.Defense();
结果如下:
试验一:
前面说用父类去实例化子类,那么我们可不可以用子类实例化自己呢?当然可以,这个体现了"里氏代换原则".子类必需能替换它的父类.
代码如下:
Forwards f = new Forwards("巴蒂尔");
Guard g = new Guard("阿尔斯通");结果和刚才的一样:
这就说明在客户端的编写过程中,其实能达到效果的不只是一种,你要选择最方便,最有效的方式.
试验二:
那么用父类去实例化子类有什么好处呢?当然 这个主要是体现多态性.在实例化的子类比较多的时候是比较实用的
比如我们要选择实例化了球员时 .这样就有很好的价值了>
代码
1: Player p=null; //修改之处.将p初始化为null.2: Console.WriteLine("请选择球员");
3: string type = Console.ReadLine();
4:5: switch (type)
6: {7: case "1":8: p = new Forwards("巴蒂尔");9: break;
10: case "2":11: p = new Guard("阿尔斯通");12: break;
13: }14: p.Attack();15: p.Defense();16: Player ym = new Translator("姚明");17: ym.Attack();18: ym.Defense();
总结:在写客户端的时候,我们要清晰我们需要那些材料,然后用怎么样的顺序,方法去实例化它.最后让实例化的
对象去做什么.这是本人的一点感悟,欢迎大家拍砖.