少爺菜鳥一枚,求輕噴。 今天在網上無意間看到一道面試題,感覺挺有意思的,題目是這樣:"請用任意一種面向對象語言實現一個電腦控制台程式,要求輸入兩個數和運算符號,輸出結果”。 第一遍的時候還在想,居然還有這麼簡單的面試題?花了幾分鐘敲了一下這個程式,代碼如下(為了方便,代碼本身不規範,很多情況並未考
少爺菜鳥一枚,求輕噴。
今天在網上無意間看到一道面試題,感覺挺有意思的,題目是這樣:"請用任意一種面向對象語言實現一個電腦控制台程式,要求輸入兩個數和運算符號,輸出結果”。
第一遍的時候還在想,居然還有這麼簡單的面試題?花了幾分鐘敲了一下這個程式,代碼如下(為了方便,代碼本身不規範,很多情況並未考慮):
1 public class Calculator { 2 3 public static void main(String[] args) { 4 System.out.println("請輸入第一個數字:"); 5 Scanner input1 = new Scanner(System.in); 6 int numberOne = input1.nextInt(); 7 System.out.println("請輸入運算符:"); 8 Scanner input2 = new Scanner(System.in); 9 String operation = input2.nextLine(); 10 System.out.println("請輸入第二個數字:"); 11 Scanner input3 = new Scanner(System.in); 12 int numberTwo = input3.nextInt(); 13 int result = 0; 14 switch (operation) { 15 case "+": 16 result = numberOne + numberTwo; 17 break; 18 case "-": 19 result = numberOne - numberTwo; 20 break; 21 case "*": 22 result = numberOne * numberTwo; 23 break; 24 case "/": 25 if (numberTwo != 0) { 26 result = numberOne / numberTwo; 27 } else { 28 result = -9999999; //表示出問題 29 } 30 break; 31 } 32 System.out.println("結果是: " + result); 33 } 34 }
然而當我再回看題目的時候,發現實際上也沒有那麼簡單。題目上表明瞭“面向對象語言”,雖然java是面向對象的語言,然而很顯然上面的解法只是單純的面向過程的解法。當我們看到一個問題的時候,總是很容易用很簡單的邏輯去解決問題(可能菜鳥都會這樣,比如少爺...),雖然這樣的答案沒有錯,然而卻沒有領略到面向對象的精髓。
那麼,面向對象的精髓又是什麼呢?
當我們在學Java的時候,老師對會說,Java你們一定要深入的去理解[封裝]、[繼承]和[多態]。
這三個特性的好處有很多很多(之後會另開文分別分析),總結來說:面向對象的編程方法就是利用這三個特性讓程式的耦合度降低,使得程式可以更容易維護,復用和擴展。
比如說上面的一段代碼,如果某一天,我不想在控制台用了,想換到web,移動端等等,那麼,上面的代碼,我們可以去復用嗎?
很多人可能會說,可以啊,功能那裡直接複製粘貼就好了嘛!
但是想想,就這麼簡單的一段倒是沒關係,如果你在一千個地方,一萬個地方都寫了這段代碼呢?(估計正常人都會瘋了...)
所以,在編程的時候,我們應該儘量去避免重覆代碼。
這個時候,我們可以考慮一下,是不是可以把裡面的業務部分和界面分離開呢?
此時,便可以考慮採用封裝,把功能從界面中分離開來,具體代碼如下:
1 public class UI { 2 public static void main(String[] args) { 3 System.out.println("請輸入第一個數字:"); 4 Scanner input1 = new Scanner(System.in); 5 int numberOne = input1.nextInt(); 6 System.out.println("請輸入運算符:"); 7 Scanner input2 = new Scanner(System.in); 8 String operation = input2.nextLine(); 9 System.out.println("請輸入第二個數字:"); 10 Scanner input3 = new Scanner(System.in); 11 int numberTwo = input3.nextInt(); 12 int result = 0; 13 result = Calculator.getResult(numberOne, operation, numberTwo); 14 System.out.println("結果是: " + result); 15 } 16 } 17 18 public class Calculator { 19 20 public static int getResult(int numberOne,String operation,int numberTwo) { 21 int result = 0; 22 switch (operation) { 23 case "+": 24 result = numberOne + numberTwo; 25 break; 26 case "-": 27 result = numberOne - numberTwo; 28 break; 29 case "*": 30 result = numberOne * numberTwo; 31 break; 32 case "/": 33 if (numberTwo != 0) { 34 result = numberOne / numberTwo; 35 } else { 36 result = -9999999; //表示出問題 37 } 38 break; 39 } 40 return result; 41 } 42 }
這樣的話,不管是用到什麼地方,至少運算這一部分的代碼相對之前那個,會更好用一些。
當然,這也只是用到了三個特性中的一個。比如說,有一天,我突然還想用一些其他的運算方式,比如說乘方,開方,求餘等等,又該怎麼做呢? 當然,我們可以選擇直接修改運算類中switch語句,直接加上一個新功能。然而,這樣真的合理嗎?比如說,switch裡面已經有成百上千中運算方式了,而且運算方式也比較複雜,你為了加多一種,就要重新編譯一次所有的運算方法,而且,還有可能不小心修改了之前實現好的東西(比如說銀行存錢的加法變成了減法,呵呵呵......),這樣就太不划算了。
所以,當我們在寫程式的時候,應該儘可能的把功能獨立開來,修改其中一個或者新增功能,對其他的不造成影響。
此時,我們可以考慮一下繼承,具體代碼如下:
1 public class Calculator { 2 3 public int getResult(int numberOne,int numberTwo) { 4 int result = 0; 5 return result; 6 } 7 } 8 9 public class Add extends Calculator { 10 11 @Override 12 public int getResult(int numberOne,int numberTwo) { 13 int result = 0; 14 result = numberOne + numberTwo; 15 return result; 16 } 17 } 18 19 public class Sub extends Calculator{ 20 @Override 21 public int getResult(int numberOne,int numberTwo) { 22 int result = 0; 23 result = numberOne - numberTwo; 24 return result; 25 } 26 }
這個時候,不管我們是要修改功能,還是新添加功能,都不會再去影響原有的功能。當然,此時還要考慮一個問題就是,怎麼知道調用的是什麼功能呢?
這個時候可以利用Java的多態特性,同時利用簡單工程模式來簡化理解。簡單工廠類代碼如下:
1 public class SimpleFactory { 2 public static Calculator createCalculator(String operation){ 3 Calculator calculator = null; 4 switch(operation){ 5 case "+": 6 calculator = new Add(); 7 break; 8 case "-": 9 calculator = new Sub(); 10 break; 11 } 12 return calculator; 13 } 14 }
客戶端代碼:
1 public class UI { 2 public static void main(String[] args) { 3 System.out.println("請輸入第一個數字:"); 4 Scanner input1 = new Scanner(System.in); 5 int numberOne = input1.nextInt(); 6 System.out.println("請輸入運算符:"); 7 Scanner input2 = new Scanner(System.in); 8 String operation = input2.nextLine(); 9 System.out.println("請輸入第二個數字:"); 10 Scanner input3 = new Scanner(System.in); 11 int numberTwo = input3.nextInt(); 12 int result = 0; 13 Calculator calculator = null; 14 calculator = SimpleFactory.createCalculator(operation); 15 result = calculator.getResult(numberOne,numberTwo); 16 System.out.println("結果是: " + result); 17 } 18 }
這個時候,不管以後是想把這個功能用在pc端還是移動端或者其他位置,只需要修改相應的界面即可,而如果想要修改裡面的功能(加法,減法等等)或者新增一些其他功能(求餘,開方等等),只需要增加相應的子類,同時修改工廠方法中的switch語句即可(簡單工廠模式也有其弊端,比如說太多運算的問題,就會重覆上文所說的switch語句那個問題,此處只是為了舉例說明)。
總結:面向對象的編程方法就是讓程式的耦合度降低,使得程式可以更容易維護,復用和擴展。(copy了上文)
PS:感覺可能有些東西還沒有說清楚,也只是回想了一下當年老師說過的慄子,只能說本文只是當做一個入門吧,以後有什麼新的想法再繼續修改。有大神有其他高見的希望指出