最近在自學設計,碰到一題目,我相信網上很多地方也能找到這個題目,題目內容如下:
農場一頭小母牛
每年生頭小母牛
母牛五歲產母牛
二十年上多少牛
請使用OO思想來解決這個問題。
這題目很有意思,為什么呢?因為讀起來朗朗上口,很順溜,哈哈,開個玩笑。
OK,下面我將結合所學的知識和技巧來描述下自己解決這個問題的過程。
名詞
從題目內容中,我們可以抽取出多個名詞,如農場、母牛等,為什么我們要把名詞抽取出來?因為在OO思想中,就是要有類或者對象,而抽取出來的名詞就有可能是我們需要的類或者對象,當然也有可能是類的屬性,這個我們就需要結合具體的情況來分析。通過名詞抽取,我確定我需要兩個類,分別是農場和母牛,我命名為Farm和Cow。
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Farm { 7 8 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Cow { 7 8 }
屬性
確定了類,接下來就需要確定類的屬性。有些時候我們可以從給的材料或者需求中直接就定義到相關類的屬性,但是在這個題目里面我們是需要慢慢的理解隱含的關系才能確定的。首先由“母牛五歲產母牛”可以確定的屬性是母牛的年齡(age),當然在這個地方是不是還有一個生育年齡呢?還有是不是有一個生育數呢?而農場呢,咋一看,貌似只有牛,那么它的屬性是牛(Cow),還是牛群(List<Cow>)呢?在我的設計里面,牛是有年齡、生育年齡、生育數三個屬性的,只不過我把生育年齡和生育數定義為常量,而農場則有牛群和經營時間兩個屬性。
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Farm { 7 8 //農場經營時間 9 private int year; 10 //牛群 11 private List<Cow> cows; 12 13 public int getYear() { 14 return year; 15 } 16 public void setYear(int year) { 17 this.year = year; 18 } 19 public List<Cow> getCows() { 20 return cows; 21 } 22 public void setCows(List<Cow> cows) { 23 this.cows = cows; 24 } 25 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Cow { 7 8 //生育年齡 9 private static final int BEARAGE = 5; 10 //生育數 11 private static final int BORNCOUNT = 1; 12 13 //年齡 14 private int age; 15 16 17 public int getAge() { 18 return age; 19 } 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 }
類之間的關系、方法
有了類,有了屬性,那么接下來我們就要去確定這些個類的方法,而類的方法往往都是由類之間的關系確定的,舉個例子,工廠模式中Factory的create方法,假如工廠生產玩具,正是因為工廠(Factory)會生產玩具(Toy),有這樣一層關系,所以Factory會有一個create方法,這個方法就返回Toy的實例。在我們的題目環境中,Farm與Cow,隨着經營時間變化,農場的牛不斷長大,長大到了5歲會生出小牛,這些小牛又不斷長大,而農場的牛群就因此在壯大,所以牛會有一個長大(growUp)方法,農場會有一個隨時間變化的方法,我把它命名為past。
隱藏(封裝)
在確定了方法之后,我們很自然的就會去想方法體里面該寫些什么?很多時候,我們會對方法的細節特別關注,牛到了五歲時,生出來的牛是不是應該分一下是最先的母牛生的,還是后面生出來的母牛生的。至少當時我就一直在摳這個細節,而后來我發現面向對象的一大特性就是封裝,隱藏一些無須關注細節,因為我們不是在計算二十年后,最先的母牛生了多少崽,而是關注農場二十年后有多少牛,當然如果問題是問你二十年后生了崽的母牛都有多少崽或孫崽等或許就需要摳這個細節了,封裝的好處就是降低耦合,避免方法不得不需要修改時而造成的牽一發而動全身,增強可擴展性。
到此,OO思想解決這個問題就基本完成了,最后寫一個main方法來測試。
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Farm { 7 8 //農場經營時間 9 private int year; 10 //牛群 11 private List<Cow> cows; 12 13 public int getYear() { 14 return year; 15 } 16 public void setYear(int year) { 17 this.year = year; 18 } 19 public List<Cow> getCows() { 20 return cows; 21 } 22 public void setCows(List<Cow> cows) { 23 this.cows = cows; 24 } 25 26 public void past(int time) { 27 while(this.year < time) { 28 this.year ++; 29 30 int j = cows.size(); 31 for(int i=0; i<j; i++) { 32 System.out.println(i); 33 Cow c = cows.get(i); 34 c.growUp(this); 35 } 36 System.out.println("第" + year + "年,農場有" + cows.size() + "頭牛"); 37 } 38 39 } 40 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Cow { 7 8 //生育年齡 9 private static final int BEARAGE = 5; 10 //生育數 11 private static final int BORNCOUNT = 1; 12 13 //年齡 14 private int age; 15 16 17 public int getAge() { 18 return age; 19 } 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public Cow(int age) { 25 super(); 26 this.age = age; 27 } 28 29 public void growUp(Farm f) { 30 this.age ++; 31 //母牛五歲生母牛 32 if(age >= BEARAGE) { 33 //每年生頭小母牛 34 for(int i=0; i<BORNCOUNT; i++) { 35 f.getCows().add(new Cow(0)); 36 } 37 } 38 } 39 }
1 /** 2 * 測試類 3 * @author LingJian 4 * 5 */ 6 public class Test { 7 8 /** 9 * 測試方法 10 * @param args 11 */ 12 public static void main(String[] args) { 13 14 List<Cow> cows = new ArrayList<Cow>(); 15 Farm f = new Farm(); 16 //農場一頭小母牛 17 cows.add(new Cow(0)); 18 f.setCows(cows); 19 20 //二十年上多少牛 21 f.past(20); 22 23 } 24 25 }
繼承和多態
若干年后,農場主發現養牛不掙錢啦,而且小牛要等到5歲的時候才生小牛,每次才生1頭,這樣生產力和生產效率都不行啊,這個時候他想養豬,養豬掙錢吶,繁殖能力也強,於是咱們又寫了個Pig類,然后把main方法改改,又過了一段時間,農場主嫌養豬也煩,想養雞養鴨,然后就會發現我們不停的改main方法,在很多項目中就是我們不停的根據需求的變動改以前的寫好的代碼,而且做得都是牽一發動全身的事情,但是如果我們能寫出可擴展性非常不錯的設計,或許客戶的需求一變動,我們只要改一個地方就完事了那該多爽,OK,回到剛剛養豬的問題,這個地方我們如果使用OO的繼承(實現)和多態的話,即可在main方法做小小的改動,就可計算出結果。最后說一個有關生育年齡和生育數的設計,這里我都是在類的屬性里面賦以常量,如果我們要提高擴展性,可增加一個配置文件,通過反射取得配置文件中的key和value,這樣每次不管是養牛也好,養豬也好,生育年齡和生育數改變只需在main方法和配置文件中稍作變動,就可以得到馴養不同動物的結果。
1 /** 2 * 可馴養的動物接口 3 * 關於抽象類和接口 4 * 腦子里有這個概念,但是沒有具體的東西可以設計為抽象類 如交通工具 5 * 一類或幾類事物的共同特征,如可馴養的 就設計為接口 6 * @author LingJian 7 * 8 */ 9 public interface Tamableness { 10 11 public void growUp(Farm f); 12 13 }
1 /** 2 * 3 * @author LingJian 4 * 5 */ 6 public class Farm { 7 8 //農場經營時間 9 private int year; 10 //可馴養動物 11 private List<Tamableness> t; 12 13 public int getYear() { 14 return year; 15 } 16 public void setYear(int year) { 17 this.year = year; 18 } 19 public List<Tamableness> getT() { 20 return t; 21 } 22 public void setT(List<Tamableness> t) { 23 this.t = t; 24 } 25 public void past(int time) { 26 while(this.year < time) { 27 this.year ++; 28 29 int j = t.size(); 30 for(int i=0; i<j; i++) { 31 System.out.println(i); 32 Tamableness c = t.get(i); 33 c.growUp(this); 34 } 35 System.out.println("第" + year + "年,農場有" + t.size() + "頭可馴養的能掙錢的動物"); 36 } 37 38 } 39 }
1 /** 2 * 不養牛 3 * @author LingJian 4 * 5 */ 6 public class Cow implements Tamableness { 7 8 //生育年齡 9 private static final int BEARAGE = 5; 10 //生育數 11 private static final int BORNCOUNT = 1; 12 13 //年齡 14 private int age; 15 16 17 public int getAge() { 18 return age; 19 } 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public Cow(int age) { 25 super(); 26 this.age = age; 27 } 28 29 @Override 30 public void growUp(Farm f) { 31 this.age ++; 32 //母牛五歲生母牛 33 if(age >= BEARAGE) { 34 //每年生頭小母牛 35 for(int i=0; i<BORNCOUNT; i++) { 36 f.getT().add(new Cow(0)); 37 } 38 } 39 } 40 }
1 /** 2 * 改養豬 3 * @author LingJian 4 * 5 */ 6 public class Pig implements Tamableness { 7 8 //生育年齡 9 private static final int BEARAGE = 8; 10 //生育數 11 private static final int BORNCOUNT = 8; 12 13 //年齡 14 private int age; 15 16 17 public int getAge() { 18 return age; 19 } 20 public void setAge(int age) { 21 this.age = age; 22 } 23 24 public Pig(int age) { 25 super(); 26 this.age = age; 27 } 28 29 30 @Override 31 public void growUp(Farm f) { 32 this.age ++; 33 if(age >= BEARAGE) { 34 for(int i=0; i<BORNCOUNT; i++) { 35 f.getT().add(new Pig(0)); 36 } 37 } 38 } 39 40 }
1 /** 2 * 測試類 3 * @author LingJian 4 * 5 */ 6 public class Test { 7 8 /** 9 * 測試方法 10 * @param args 11 */ 12 public static void main(String[] args) { 13 14 List<Tamableness> list = new ArrayList<Tamableness>(); 15 Farm f = new Farm(); 16 //養什么 就new什么 17 list.add(new Pig(0)); 18 f.setT(list); 19 20 21 f.past(20); 22 23 } 24 25 }