少爷菜鸟一枚,求轻喷。
今天在网上无意间看到一道面试题,感觉挺有意思的,题目是这样:"请用任意一种面向对象语言实现一个计算机控制台程序,要求输入两个数和运算符号,输出结果”。
第一遍的时候还在想,居然还有这么简单的面试题?花了几分钟敲了一下这个程序,代码如下(为了方便,代码本身不规范,很多情况并未考虑):
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:感觉可能有些东西还没有说清楚,也只是回想了一下当年老师说过的栗子,只能说本文只是当做一个入门吧,以后有什么新的想法再继续修改。有大神有其他高见的希望指出