面向对象的理解
三大特征
面向对象三大基本特征:封装、继承和多态
封装:将客观事物封装成抽象的类,不允许外部程序直接访问对象内部信息,而是通过类提供的方法来实现对内部信息的操作和访问。通过封装,可以隐藏类的成员变量和实现细节,规范使用者的行为,限制了不合理的访问。
继承:实现代码复用,在Java中通过extends实现,继承提高代码的可扩展性,很多开源框架的扩展接口都是通过继承父类来完成的 但同时继承也有很多缺点:继承是侵入性的。只要继承,就必须拥有父类的所有属性和方法;降低代码的灵活性,子类必须拥有父类的属性和方法。也增强了耦合性。当父类的常量、变量和方法被修改时,需要考虑子类的修改,而且在缺乏规范的环境下,这种修改可能会导致大段的代码需要重构。
多态:多态的实现与继承有关,在设计程序时,我们可以将参数的类型定义为父类型。在调用程序时,则可以根据实际情况,传入该父类型的某个子类型的实例。对于子类型,则要根据它自身的特征,重写父类的某些方法,或实现抽象类/接口的某些抽象方法。多态提高了代码的维护性,提高了代码的扩展性
若想在java中实现多态需要三个条件: 1. 需要有继承关系的存在。 2. 需要有方法的重写。 3. 需要有父类的引用指向子类对象。
面向对象例题
为了体现面向对象设计思想可以考虑下题:
请用任意一种面向对象语言实现一个计算器控制台程序,要求输入两个数和运算符号,得到结果?
首先要保证代码规范,随后注意一下几点:
- 可维护
- 可复用
- 可扩展
- 灵活性强
通常设计的代码如下:
import java.util.Scanner;
public class Program {
public static void main(String[] args){
try{
var sc = new Scanner(System.in);
System.out.println("请输入数字A: ");
String strNumberA = sc.nextLine();
System.out.println ("清迭拝迄算符号(+、-、*、/): ");
String strOperate = sc.nextLine();
System.out.println ("靖輸入数字B: ");
String strNumberB = sc.nextLine();
String strResult = "";
switch (strOperate) {
case "+":
strResult =String.valueOf(Double.parseDouble(strNumberA) + Double.parseDouble(strNumberB));
break;
case "-":
strResult = String.valueOf(Double.parseDouble(strNumberA) - Double.parseDouble(strNumberB));
break;
case "*":
strResult = String.valueOf(Double.parseDouble(strNumberA) * Double.parseDouble(strNumberB));
break;
case "/":
if (strNumberB != "0")
strResult = String.valueOf(Double.parseDouble(strNumberA)
/ Double.parseDouble(strNumberB));
else
strResult = "除数不能为0";
break;
}
System.out.println ("结果是: " + strResult) ;
}catch(Exception ex){
System.out.println("您的输入有错误:" + ex.getMessage());
}
}
}
上述代码
如果我们再写一个计算器,只是把代码单纯的复制过去,会大大增加重复代码量,给维护带来巨大压力。这个时候可以思考,有哪些与控制台有关,哪些与计算机功能有关?即让计算和显示分开,即业务逻辑和界面逻辑分开,使其耦合度下降,容易维护和扩展。
代码如下:
import java.util.Scanner;
class Opreation{
public static String GetResult(String strNumberA,String strNumberB,String strOperation){
String strResult = "";
switch (strOperation) {
case "+":
strResult =String.valueOf(Double.parseDouble(strNumberA) + Double.parseDouble(strNumberB));
break;
case "-":
strResult = String.valueOf(Double.parseDouble(strNumberA) - Double.parseDouble(strNumberB));
break;
case "*":
strResult = String.valueOf(Double.parseDouble(strNumberA) * Double.parseDouble(strNumberB));
break;
case "/":
if (strNumberB != "0")
strResult = String.valueOf(Double.parseDouble(strNumberA)
/ Double.parseDouble(strNumberB));
else
strResult = "除数不能为0";
break;
}
return strResult;
}
}
public class Program {
public static void main(String[] args){
try{
var sc = new Scanner(System.in);
System.out.println("请输入数字A: ");
String strNumberA = sc.nextLine();
System.out.println ("清迭拝迄算符号(+、-、*、/): ");
String strOperation = sc.nextLine();
System.out.println ("靖輸入数字B: ");
String strNumberB = sc.nextLine();
String strResult=Opreation.GetResult(strNumberA,strNumberB,strOperation);
System.out.println ("结果是: " + strResult);
}catch(Exception ex){
System.out.println("您的输入有错误:" + ex.getMessage());
}
}
}
可以看到,这样就可以把业务和界面分离了,当你需要在其他地方运用到计算器功能时,只需要导入Opreation类即可。这里运用到了OOP三大特性之一的封装。
但是该代码可以进行进一步修改,运用到其他两大特性,以此做到更灵活的扩展和修改
import java.util.Scanner;
abstract class Opreation{
String numberA;
String numberB;
public String getNumberA() {
return numberA;
}
public String getNumberB() {
return numberB;
}
public void setNumberA(String numberA) {
this.numberA = numberA;
}
public void setNumberB(String numberB) {
this.numberB = numberB;
}
//抽象方法
public abstract String GetResult();
}
//加法
class OperationAdd extends Opreation{
public OperationAdd(){}
@Override
public String GetResult() {
String strResult =String.valueOf(Double.parseDouble(numberA) + Double.parseDouble(numberB));
return strResult;
}
}
//减法
class OperationSub extends Opreation{
@Override
public String GetResult() {
String strResult = String.valueOf(Double.parseDouble(numberA) - Double.parseDouble(numberB));
return strResult;
}
}
//乘法
class OperationMul extends Opreation{
@Override
public String GetResult() {
String strResult;
strResult = String.valueOf(Double.parseDouble(numberA) * Double.parseDouble(numberB));
return strResult;
}
}
//除法
class OperationDiv extends Opreation{
@Override
public String GetResult() {
String strResult;
if (numberB != "0")
strResult = String.valueOf(Double.parseDouble(numberA)
/ Double.parseDouble(numberB));
else
strResult = "除数不能刃O";
return strResult;
}
}
class OpreationFactory{
static final OpreationFactory opreationFactory = new OpreationFactory();
public Opreation CreateOperation(String strOperation){
Opreation opreation = null;
switch (strOperation) {
case "+":
opreation=new OperationAdd();
break;
case "-":
opreation=new OperationSub();
break;
case "*":
opreation=new OperationMul();
break;
case "/":
opreation=new OperationDiv();
break;
}
return opreation;
}
}
public class Program {
public static void main(String[] args){
var sc = new Scanner(System.in);
System.out.println("请输入数字A: ");
String strNumberA = sc.nextLine();
System.out.println ("清迭拝迄算符号(+、-、*、/): ");
String strOperation = sc.nextLine();
System.out.println ("靖輸入数字B: ");
String strNumberB = sc.nextLine();
Opreation opreation= OpreationFactory.opreationFactory.CreateOperation(strOperation);
opreation.setNumberA(strNumberA);
opreation.setNumberB(strNumberB);
System.out.println(opreation.GetResult());
}
}
我可以将运算类Operation作为父类,然后就可以利用继承,派生出加、减、乘、除四类,并且利用多态,重写父类的GetResult方法。再利用一个简单的工厂模式,解决实例化问题。
这样,再继续增加其他运算符号,只需要增加运算子类,并增加工厂类的switch分支即可,提高了扩展性,更加方便修改和维护。