JAVA物件導向_封裝_繼承_抽象類別_多型的概念

在物件導向程式設計當中
會探討到所謂  「多形」的概念
那一般會和抽象類別一起探討


其實每一天的任務做的事情就牽扯到這些物件導向設計的觀念
可以用下面的例子來做簡易示範


前人工程師們很辛苦的設計出如下架構

今天若我們想要去滿足使用者輸入特定關鍵字來對應計算出不同形狀的面積
此時我們可以怎麼去做開發前的規劃呢???

假設user可能會輸入  三角形、正方形、圓形等等的時候
各有各自不同面積計算的公式和對應傳入的參數

所有的形狀都有計算面積的機制!!!!!!!!





藉此我們創建一個抽象類別命名為 Shape

抽象類別包含以下幾個特徵:
1.無法定義明確細部動作的類別
2.無法產生物件實體
3.包含抽象方法(不具實作細節的方法)的類別
4.以其作為父類繼承的子類必須實作其抽象方法



由下方的UML 進行程式規格設計撰寫
使用staruml 繪製



Shape 抽象類別

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;
//無法定義明確細部動作的類別,所以也無法產生物件實體
//包含抽象方法的類別
/**
 *
 * @author chous
 */
public abstract class Shape {

    protected double area;

    public abstract void calcArea();
    
    public double getArea(){
        return area;
    }
    
    public void printArea(){
        System.out.println("Area is : " + area);
    }
}

(PS: 抽象類當中也可以具有實作方法!!!!)

由於後續三個不同種類形狀子類都會需要回傳面積
因此使用protected修飾來讓子類們可共享有Shape父類這個屬性


Circle 類

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

/**
 *
 * @author chous
 */
public class Circle extends Shape{
    private double r;

    public Circle() {
        this.r = 0;
    }
    
    public Circle(double r){
        this.r = r;
    }

    public void setRadius(double r){
        this.r = r;
    }
    
    @Override
    public void calcArea() {
        area = Math.pow(this.r, 2) * Math.PI;
    } 
}

這裡我們透過定義建構子多載
讓Cirle可以於實體化的同時去指派半徑的值
或是讓其透過將半徑屬性封裝後對外存取介面setRadius() 的方法
也可以達到同等功能
下方則是去實作Shape父類中定義的抽象方法calcArea()


其餘以此類推設計




Triangle 類

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

/**
 *
 * @author chous
 */
public class Triangle extends Shape{
    private double bottom,height;
    
    public Triangle(){
        bottom = 0;
        height = 0;
    }
    
    public Triangle(double b,double h){
        bottom = b;
        height = h;
    }
    
    public void setTriangleParameter(double bottom , double height){
        this.bottom = bottom;
        this.height = height;
    }
    
    @Override
    public void calcArea() {
        area = (this.bottom * this.height)/2;
    }
}


Square 類


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

/**
 *
 * @author chous
 */
public class Square extends Shape{
    
    private double side;

    public Square(){
        this.side = 0;
    }
    
    public Square(double side){
        this.side = side;
    }
    
    public void setSquareParameter(double side){
        this.side = side;
    }

    @Override
    public void calcArea() {
        area = Math.pow(this.side, 2);
    }
}


主要程式區域

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

/**
 *
 * @author chous
 */
public class TestMain {

    public static void main(String[] args) {
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        Shape s;

        System.out.println("請輸入目前要進行計算的形狀種類:");
        try {
            String str = input.readLine();
            System.out.println("當前所選之形狀為:" + str);
            if (str.equals("Circle")) {
                System.out.println("請輸入半徑:");
                Scanner inputRadius = new Scanner(System.in);
                double r = inputRadius.nextDouble();
                s = new Circle(r);
                s.calcArea();
                s.printArea();
            } else if (str.equals("Square")) {
                System.out.println("請輸入正方形邊長:");
                Scanner inputSide = new Scanner(System.in);
                double side = inputSide.nextDouble();
                s = new Square(side);
                s.calcArea();
                s.printArea();
            } else if (str.equals("Triangle")) {
                System.out.println("請輸入三角形的底:");
                Scanner inputBottom = new Scanner(System.in);
                double b = inputBottom.nextDouble();
                System.out.println("請輸入三角形的高:");
                Scanner inputHeight = new Scanner(System.in);
                double h = inputHeight.nextDouble();              
                s = new Triangle(b, h);
                s.calcArea();
                s.printArea();
            }
        } catch (IOException ex) {
            System.out.println(ex);
        }

    }
}


於是這套系統運行了快要2~3年甚至數十年
前人工程師們一個接著一個走了

後來換來新一批工程師接手這項系統的維護(這只是小型示意~ 請鞭小力一點!!)

某一天突然使用者說他需要擴充能夠獲得矩形面積的功能
要修改這區塊程式

此時我們工程人員需要回過頭來重新思考如何
利於維護不撰寫多餘程式碼為前提
去進行需求開發上的調整

注意 !!!  不撰寫多於程式碼 並不等於 不寫程式碼
而是為了去提升程式碼可以重複利用的特性~~~


後來 新工程師發現
架構需要調整為下方UML示意圖
其實矩形的定義涵蓋了正方形
所以可以將矩形往上提 而原有的正方形則降一級改為繼承新升上去的矩形
矩形也和其他圓形、三角形繼承形狀 的 Base



矩形 事實上傳入的值有 寬 和 高
正方形 由於原先設計以及定義其邊長都是一樣的
但計算方式是可被重複使用的





Rectangle 類


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

/**
 *
 * @author chous
 */
public class Rectangle extends Shape{
    protected double w,h;
            
    public Rectangle(){
        w = 0;
        h= 0;
    }
    
    public Rectangle(double w, double h){
        this.w = w;
        this.h = h;
    }

    public void setRectangleParameter(double w,double h){
        this.w = w;
        this.h = h;
    }
    
    @Override
    public void calcArea() {
        area = this.w * this.h;
    }
}






Square 類


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

/**
 *
 * @author chous
 */
public class Square extends Rectangle{
    
    public Square(double side){
        super.w = side;
        super.h = side;
    }
    
    public void setSquareParameter(double side){
        super.w = side;
        super.h = side;
    }
}




主要程式區域


 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package shape;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;

/**
 *
 * @author chous
 */
public class TestMain {

    public static void main(String[] args) {
        BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
        Shape s;

        System.out.println("請輸入目前要進行計算的形狀種類:");
        try {
            String str = input.readLine();
            System.out.println("當前所選之形狀為:" + str);
            if (str.toLowerCase().equals("circle")) {
                System.out.println("請輸入半徑:");
                Scanner inputRadius = new Scanner(System.in);
                double r = inputRadius.nextDouble();
                s = new Circle(r);
                s.calcArea();
                s.printArea();
            } else if (str.toLowerCase().equals("square")) {
                System.out.println("請輸入正方形邊長:");
                Scanner inputSide = new Scanner(System.in);
                double side = inputSide.nextDouble();
                s = new Square(side);
                s.calcArea();
                s.printArea();
            } else if (str.toLowerCase().equals("triangle")) {
                System.out.println("請輸入三角形的底:");
                Scanner inputBottom = new Scanner(System.in);
                double b = inputBottom.nextDouble();
                System.out.println("請輸入三角形的高:");
                Scanner inputHeight = new Scanner(System.in);
                double h = inputHeight.nextDouble();              
                s = new Triangle(b, h);
                s.calcArea();
                s.printArea();
            }else if (str.toLowerCase().equals("rectangle")){
                System.out.println("請輸入矩形之寬:");
                Scanner inputWidth = new Scanner(System.in);
                double w = inputWidth.nextDouble();
                System.out.println("請輸入矩形之高:");
                Scanner inputHeight = new Scanner(System.in);
                double h = inputHeight.nextDouble();
                s = new Rectangle(w,h);
                s.calcArea();
                s.printArea();
            }
        } catch (IOException ex) {
            System.out.println(ex);
        }

    }
}











參考學習連結:

[Java]抽象類別(基本範例解說)
https://ithelp.ithome.com.tw/articles/10184934


STARUML
https://stackoverflow.com/questions/18497197/how-to-create-a-abstract-method-in-staruml-5

https://www.jianshu.com/p/617f6f413452



留言

這個網誌中的熱門文章

何謂淨重(Net Weight)、皮重(Tare Weight)與毛重(Gross Weight)

Architecture(架構) 和 Framework(框架) 有何不同?_軟體設計前的事前規劃的藍圖概念

經得起原始碼資安弱點掃描的程式設計習慣培養(五)_Missing HSTS Header