讨论沙发床的面向对象模拟

    这是一个很经典的问题,很简单,通过这个问题我们来认识面向对象的一些设计上的知识。问题是这样的:有一种沙发床,可以供像去坐沙发一样去坐,也可以供像睡床一样去睡,请用面向对象的语言去模拟。
     最常规的想法是这样的:
interface Sofa{
 void sit();
}
interface Bed{
 void sleep();
}
class DefaultSofa implements Sofa{
 public void sit(){
  System.out.println("Sitting");
 }
}
class DefaultBed implements Bed{
 public void sleep(){
  System.out.println("Sleeping");
 }
}
class SofaBed implements Sofa,Bed{
 public void sit(){
  System.out.println("Sitting");
  }
 public void sleep(){
  System.out.println("Sleeping");
 }
}
    以上代码看似完美,事实上在讲述java语法时,这个实现也确实是个很好的阐述java中如何避开多继承的例子。然而,聪明的读者一定可以嗅到这段设计的臭味了,DefaultSofa类和SofaBed类的sit方法实现采用了copy+paste的方式,DefaultBed类和SofaBed类的sleep方法也一样。

   一个好的设计必须能很好的复用代码。显然这样的设计在系统架构师眼里就不再那么完美了。 也有部分聪明的读者甚至开始怀疑java的整体架构了,开始认为接口是否并不是像sun说的那么高明。 这样的想法很自然,这起码说明读者已开始思考到了这种设计的弊端。然而当你进一步了解了java接口的真正用意后你就会改变这种看法了。
   先让我们来研究研究java接口。
   接口和类的最重要的区别是,接口仅仅描述方法的特征,而不是给出方法的实现;而类不仅给出方法的特征,而且给出方法的实现。因此,接口把方法的特征和方法的实现分割开来。这种分割,体现在接口常常代表一个角色,它包装与该角色相关的操作和属性,而实现这个接口的类便是扮演这个角色的演员。一个角色可以由不同的演员来演,而不同的演员之间除了扮演一个共同的角色之外,并不要求有任何其他的共同之处。(出自<<java与模式>>)
    有什么样的需求就会有什么样的设计。
    所描述问题的需求为:沙发的sit方法和沙发床的sit方法具有同样的实现;床的sleep方法和沙发床的sleep方法具有同样的实现;只能坐在沙发上;只能睡在床上。
    根据上面所说,就应该思考sit和sleep的这个职责到底该由谁来完成了。事实上沙发是没有坐的方法的,应该是人去坐沙发,宠物去坐沙发;人去睡床,宠物去睡床。由此,可以考虑下面的设计
interface SitAble{
      void sit(Sofa sofa);
}
interface SleepAble{
      void sleep(Bed bed);
}
interface Sofa{
}
interface Bed{
}
class SofaBed implements Sofa,Bed{
}
class Person implements SitAble,SleepAble{
     public void sit(Sofa sofa){
     }
     public void sleep(Bed bed){
     }
}
class Pet implements SitAble,SleepAble{
     public void sit(Sofa sofa){
     }
     public void sleep(Bed bed){
     }
}

        结论:这样的设计解决了代码不能复用的问题,同时也符合具体实际。缺点就是类和接口多了点,这很正常,因为每个类可能还有很多别的代码,我们在这里仅关心问题的这些方面。一般来说要获得很好的架构,往往要去挖掘一些隐藏类。欢迎大家讨论和批评

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值