面向对象编程
优点
- 可维护:可在不影响别的模块的情况下修改只想改的地方
- 可复用:可以在别处被调用
- 可扩展:可在不影响别的模块的情况下添加
- 灵活性好:当需求有轻微改动时,可满足需求
如何实现以上优点?
以一个计算器小程序为例,实现输入两个数和运算符后进行四则运算的功能。
// 菜鸟代码
// 注意每个变量名都有意义,注意异常产生
public static void main(String[] args) {
try {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字a:");
int numberA = scanner.nextInt();
System.out.print("请输入运算符:");
String operation = scanner.next();
System.out.print("请输入数字b:");
int numberB = scanner.nextInt();
int result = 0;
switch (operation) {
case "+":
result = numberA + numberB;
break;
case "-":
result = numberA - numberB;
break;
case "*":
result = numberA * numberB;
break;
case "/":
result = numberA / numberB;
break;
}
System.out.printf("结果是:{%d}", result);
} catch (Exception e) {
System.out.println("输入错误" + e.getMessage());
}
}
分析这段代码,会发现该程序实现的两个功能,即读取用户输入和计算结果,放在同一个类中使得该类略显臃肿,功能不单一。
可复用
- 封装:将有相似功能的程序封装在一个方法、类中;例如,在计算器小程序中,将加减乘除封装在一个类中,将接收用户输入的模块封装在另一个类中
// 封装后
/* 客户端 */
public class Demo extends Operation{
public static void main(String[] args){
try {
Scanner scanner = new Scanner(System.in);
System.out.print("请输入数字a:");
int numberA = scanner.nextInt();
System.out.print("请输入运算符:");
String operation = scanner.next();
System.out.print("请输入数字b:");
int numberB = scanner.nextInt();
int result = Operation.getResult(numberA,numberB,operation);
System.out.printf("结果是:{%d}", result);
} catch (Exception e) {
System.out.println("输入错误" + e.getMessage());
}
}
}
/* 运算端 */
class Operation{
public static int getResult(int numberA, int numberB, String operation) {
switch (operation) {
case "+":
return numberA + numberB;
case "-":
return numberA - numberB;
case "*":
return numberA * numberB;
case "/":
return numberA / numberB;
default:
return 0;
}
}
}
上面的代码中,如果要添加一个功能(如求平方),需要将所有的运算方法都编译,容易在修改过程中造成原有代码的误操作,维护性、扩展性都很差。
可维护、可扩展
可将原Operation类中的四个方法又独立成四个类,继承Operation类,如下:
public class Operation {
private double numberA;
private double numberB;
public double getNumberA() {
return numberA;
}
public void setNumberA(double numberA) {
this.numberA = numberA;
}
public double getNumberB() {
return numberB;
}
public void setNumberB(double numberB) {
this.numberB = numberB;
}
public double getResult() {
return 0;
}
}
class operationAdd extends Operation {
@Override
public double getResult() {
return getNumberA() + getNumberB();
}
}
class operationMinus extends Operation {
@Override
public double getResult() {
return getNumberA() - getNumberB();
}
}
class operationMultiple extends Operation {
@Override
public double getResult() {
return getNumberA() * getNumberB();
}
}
class operationDivide extends Operation {
@Override
public double getResult() {
if (getNumberB() == 0) {
try {
throw new Exception("输入有误: 除数不能为0");
} catch (Exception e) {
e.printStackTrace();
}
}
return getNumberA() / getNumberB();
}
}
以上代码实现了继承和多态的作用。
- 继承:一个类是另一个类的父类,则子类可使用父类的所有public属性和方法
- 多态:子类继承父类时重写其方法以实现不同作用
那么,在运行中如何确定调用哪个类?
简单工厂模式
简单工厂模式:将有相似功能的类分别封装,使其继承一个父类;这样修改或添加某个类时不会影响到其他功能类。
建立一个名为工厂的类,将能被调动的类(加减乘除)放入其中,用switch
选择。
public class OperationFactory {
public static Operation createOperation(String operation) {
switch (operation) {
case "+":
return new operationAdd();
case "-":
return new operationMinus();
case "*":
return new operationMultiple();
case "/":
return new operationDivide();
default:
return new Operation();
}
}
}
而主类只需变成如下:
public class Demo extends Operation{
public static void main(String[] args){
Operation operation = OperationFactory.createOperation("+");
operation.setNumberA(1);
operation.setNumberB(2);
System.out.println(operation.getResult());
}
}
其UML图如下:
小结
- 方法、类尽量实现一个功能
switch
等选择的情况下可考虑设计简单工厂方法