随笔 - 11  文章 - 33  trackbacks - 0
<2007年9月>
2627282930311
2345678
9101112131415
16171819202122
23242526272829
30123456

常用链接

留言簿(1)

随笔分类

随笔档案

文章档案

搜索

  •  

最新随笔

最新评论

阅读排行榜

评论排行榜

本文假定读者已经了解有关正方形不是长方形的相关内容。
        
        之前人们讨论的正方形长方形的问题的关键在哪里?我觉得就在于改动长方形的边的长度。我们可以这么考虑一下,一个长方形的instance的边长应该是可变的吗?我觉得一旦一个长方形的边长改变之后它就成了另一个长方形了(一个新的instance)。所以长方形类里面不应该有改变其边长的方法,一个长方形实例各个的边长应当在new它的时候确定下来,并且它们应当是immutable的。基于这种考虑,我设计的长方形和正方形的类如下所示:
//长方形
public class Rectangle {
  private final int width;
  private final int height;
 
  public Rectangle(int width, int height) {
    this.width = width;
    this.height = height;
  }
 
  public int getWidth() {
    return width;
  }

  public int getHeight() {
    return height;
  }
 
  public int getArea() {
    return width*height;
  }
}

//正方形
public class Square extends Rectangle{
  private final int side;
 
  public Square(int side) {
    super(side, side);
    this.side = side;
  }
 
  public int getSide() {
    return side;
  }
}

        这种继承关系就既符合现实中的父子关系也遵循LSP。之所以这么设计,我的想法是一个类所具有的方法不应当能够改变其本质。比如有一个Men类,它可以有eat(),sleep(),work(),makeLovewith(Person p)方法,但是如果你在里面定义denatureToWomen(),denatureToEunuch()就很不恰当了,因为这改变了其本质,导致这个Men的实例不再属于Men类(至少已经和现实不吻合)了。除非这两个方法不能改变该实例本质,否则在Men里面定义这两个方法本身就是有问题的。不过如果用下面这种方式定义也许可行:
public Women denatureToWomen() {
  Women w = new Women();
  //set attributes here
  return w;
}

public Eunuch denatureToEunuch() {
  Eunuch e = new Eunuch();
  //set attributes here
  return e;
}

这样一来,调用denatureToWomen()会产生一个新的实例,原来的那个Men实例依然存在,这和现实生活依然不吻合,现实生活中一个实例不光可以上型(upcast),还可以平行型,寒。。。

总之一句话,一个类的方法不应该改变其实例的本质。

posted on 2007-09-20 16:33 teasp 阅读(2720) 评论(13)  编辑  收藏 所属分类: Java学习

FeedBack:
# re: 正方形不是长方形的终极解决办法 2007-09-20 16:43 千里冰封
呵呵,有意思  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-20 18:29 GandofYan
new Square (4,5);

会有什么结果呢?  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-20 18:45 teasp
@GandofYan
兄弟啊,Square只有一个构造方法,你说的这句有语法错误哦。  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-20 19:55 GandofYan
@teasp


哦,sorry,我一直以为构造方法子类是继承的
我说错了:)  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-20 20:38 黑蝙蝠
makeLovewith你取的方法名字真酷 呵呵

还是没明白你到底想表达什么》??  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-20 21:33 teasp
@黑蝙蝠

呵呵,我不知道你有没有看过关于正方形不是长方形的讨论,网上有的,另外《Java与模式》里面第79页左右就是讲这个问题的。如果你看过相关的内容,应该能明白我要表达的意思了。  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-20 21:49 teasp
没看过相关讨论的可以看看这个先:

长方形有二个属性长和宽。并有一个设置长的方法和设置宽的方法,还有一个求面积的方法.
像下面
private int length;
private int width;
public void setLength(int lenght) {
this.length = lenght;
}
public void setWidth(int width) {
this.width= width;
}
public int getArea() {
return this.length * this.width;
}
如果说正方形是长方形的子类。为了保证正方形长和宽相等,那对应于正方形的二设置长宽的个方法就得改成
public void setLength(int lenght) {
this.length = lenght;
this.width= lenght;
}
public void setWidth(int width) {
this.length = width;
this.width= width;
}
那我们想想用户使用时候的情景。 我们都知道长方形的面积等于长与宽的积。那当我们用长方形的时候我们会这样用
Rectangle rectangle = new Rectangle();
rectangle.setLength(5);
rectangle.setWidth(4);
我们想知道面积是多少我们就可以
rectangle.getArea();
得到的是20,当然结果是非常正确的。
但想想如果我们把一个正方形的实例给用户用的时候会怎么样
Rectangle rectangle = new Square(); //注意,这里体显代换原则。用户根本不知道真正的实例是正方形,用户只知道长方形的事情。
rectangle.setLength(5);
rectangle.setWidth(4);
我们想知道面积是多少我们就可以
rectangle.getArea();
得到的结果却是 16 ,这违背了长方形的面积是长与宽之积的原则。用户就不会明白为什么我设置了长是5宽是4得到的答案却是16 ?? 与前提不符
所以正方形不能代替长方形出现在这个地方。
也就是说正方形不应当看作是长方形的子类。
  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-21 10:27 辛科
认同楼主  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-21 16:38 dominobaby
继承是泛化,是扩展,结果是:女人不是人,但翠花是人!
作者的看法确实可取,边长似乎确实是方形的标志性。
但是这样的话,哪些作为不可变量很难确定。比如:矮子是不是人?想一个矮子类,就得把高矮也定为不可变量,可是这就跟人的生长特性矛盾了。
  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-21 17:51 teasp
楼上说得很有道理,最关键的问题是我们不知道哪些特性才是一个类的标志。因为现实世界太复杂了,简直不可模仿  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-23 20:21 zenny_chen
我认为将正方形作为长方形的子类本身是一个错误的概念。
实际上我们应该将面向对象中的继承与离散数学的集合论联系起来:
例如有集合A={a, b, c}, B={a, b}。这里显然B是A的子集。然而如果用面向对象的方法将这两个集合构造为两个具有继承关系的类结构的话很显然,应该将集合B作为父类而将集合A作为B的子类。
因此,像public class Square extends Rectangle这种写法欠妥。作为正方形其元素就只要一个边长,而矩形则要两个。因此,根据上面的集合,可以列出Square={a}, Rectangle={a, b}。很显然,应该将正方形作为父类,而矩形作为正方形的子类。(当然,作为集合元素应该为集合类型,而不是组合。不过在软件设计建模上暂且就如此表示)。

在做面向对象的设计时,不应该死板地去看待现有逻辑,尽管我们一直认为正方形是矩形的一个子类(特殊类)。但根据继承的概念——子类继承父类的所有属性和操作这一概念,在很多时候集合中的子集关系与面向对象中的继承关系是相反的。

  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-23 20:26 zenny_chen
对了。在这里说明一下,上面提到的“Square={a}, Rectangle={a, b}”中Square和Rectangle是指正方形与矩形的边长集,而不是指正方形与矩形的集合。
  回复  更多评论
  
# re: 正方形不是长方形的终极解决办法 2007-09-24 10:45 真的遵循LSP?
长方形在这里只是举个例子 ,在一个类中改变一个类的属性的方法是很正常的需求,既然原来的结论:
"也就是说正方形不应当看作是长方形的子类。 "

那正方形类就不应改继承长方形类.  回复  更多评论
  

只有注册用户登录后才能发表评论。


网站导航: