关于客户端编写的问题

最近在敲大话设计模式中的C#代码.我是在看UML图去敲代码的.由于UML图中没有画出客户端的图.
导致写客户端的代码时,很是费力.不清楚该怎么写.没有一点的章法.总是蒙几句.最后运行出来了,感觉就是
对的,也不知道自己是怎么写出来的.让我从头写一次.和上次的感觉还是一样的.我仔细分析了一下.

关于为什么不会写客户端.我感觉这不是一个单纯的编码问题.也不是你对语言的理解不深刻.

其实是你对程序的过程理解不深刻,对各个类的职能不理解.对面向对象不理解.

我这里只讨论控制台程序.
比如一个程序你不会写客户端,其实你就是不知道客户是如何调用它的.
这个面向对象的技术有很大关系.你的程序已近都把你将要用的类,功能编写完毕了.那么客户端是什么呢?
其实就是你如何去实例化这些类,那些类该实例化,在那个时候实例化.让他们变成能工作的具体对象.然后
是如何利用这些对象的方法.也就是功能.

我们往往感到困惑的地方就是如何实例化这些类.很多的时候客户端要体现OO的多态特征.要用父类去实
例化子类,如果你直接运用了子类实例化自己.其实反映出来的就是你对多态的不理解.为什么要用多态,
个人理解一是:为了程序的灵活性,父类可以实例化很多的子类,不用一个一个的判断我要用到那个子类,
然后再去实例化,减轻了客户端的负担.二是: 为了方便调用,调用的时候,我客户端不需要知道你到底是那个
子类的方法,只需要调用父类的同样的方法,就能控制子类.

能快速高效的把客户端写好,证明这个程序的思路你就已近理解了.下面举一个例子来说明一下:

就拿设计模式中的<适配器模式>来说(c#)

首先你先设计出各个类.就好像是你要做饭先把各个料备好.

  1: //抽象父类球员,每个人都有进攻,防守方法
  2:     abstract class Player
  3:     {
  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 Name
  6:         {
  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();

结果如下:

image

试验一:

前面说用父类去实例化子类,那么我们可不可以用子类实例化自己呢?当然可以,这个体现了"里氏代换原则".子类必需能替换它的父类.
代码如下:
Forwards f = new Forwards("巴蒂尔");
Guard g = new Guard("阿尔斯通");

结果和刚才的一样:

image这就说明在客户端的编写过程中,其实能达到效果的不只是一种,你要选择最方便,最有效的方式.

试验二:
那么用父类去实例化子类有什么好处呢?当然 这个主要是体现多态性.在实例化的子类比较多的时候是比较实用的
比如我们要选择实例化了球员时 .这样就有很好的价值了>
代码

  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();

总结:在写客户端的时候,我们要清晰我们需要那些材料,然后用怎么样的顺序,方法去实例化它.最后让实例化的
对象去做什么.这是本人的一点感悟,欢迎大家拍砖.

posted on 2010-12-08 11:20  技术无敌  阅读(262)  评论(0编辑  收藏  举报