隨筆 - 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 閱讀(2731) 評論(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?
          長方形在這里只是舉個例子 ,在一個類中改變一個類的屬性的方法是很正常的需求,既然原來的結論:
          "也就是說正方形不應當看作是長方形的子類。 "

          那正方形類就不應改繼承長方形類.  回復  更多評論
            
          主站蜘蛛池模板: 北安市| 博客| 兴安县| 久治县| 秭归县| 雷州市| 东安县| 新津县| 浠水县| 微博| 沾益县| 招远市| 阿拉善左旗| 襄垣县| 隆德县| 北流市| 石景山区| 甘泉县| 蒙阴县| 平利县| 方山县| 射洪县| 临夏县| 鸡西市| 忻城县| 万山特区| 张北县| 怀集县| 丽江市| 台中市| 时尚| 莲花县| 南康市| 平阳县| 沈阳市| 昌黎县| 且末县| 梓潼县| 金寨县| 通河县| 班玛县|