iT邦幫忙

2022 iThome 鐵人賽

DAY 3
0

軟體開發的不變真理─改變

設計程式時,當我們收到需求之後,要做出來很容易,要做得好的上下限卻差很多。
如果你能確保這軟體寫完用一次就不需要了,未來不支持更新,那你可能可以忽略這一切,也不需要設計模式,反正不需要擴展也不用維護XD;但這軟體就相當於死了,只要還活著,面對的就是不停的改變;擴展─需要新功能、要跨到新的平台,是改變;維護─環境變了,對接的其他工具變了,重構程式碼,也是改變;因此,程式的設計要考慮彈性,不能牽一髮動全身,改個用法就要整篇重寫,做好的測試也都要重來。
書中以一個充滿各種鴨子遊戲舉例,為了不要重複撰寫多個鴨子的類別,來個簡單明瞭的base class鴨子,其他鴨子則是繼承它,並覆寫(override)外觀部分:
(以下由C++撰寫)

#include <iostream>

using namespace std;

class Duck
{
    public:
        void quack()
        {
            cout << "quack!" << endl;
        }
        void swim()
        {
            cout << "swim in the water!" << endl;
        }
        void display()
        {
            cout << "a normal duck" << endl;
        }
};

class MallardDuck: public Duck
{
    public:
        void display()
        {
            cout << "a green head duck" << endl;
        }
};

class RedheadDuck: public Duck
{
    public:
        void display()
        {
            cout << "a red head duck" << endl;
        }
};

int main()
{
    Duck duck;
    duck.quack();
    duck.swim();
    duck.display();

    MallardDuck mallard;
    mallard.quack();
    mallard.swim();
    mallard.display();

    RedheadDuck redhead;
    redhead.quack();
    redhead.swim();
    redhead.display();
    return 0;
}
// -----output-----
quack!
swim in the water!
a normal duck
quack!
swim in the water!
a green head duck
quack!
swim in the water!
a red head duck

此時,若想為鴨子加一個feature:fly(),定義為cout<<"fly in sky"<<endl;,所有繼承的鴨子都會多了此feature;而若現在鴨子有10種,分成了兩類,有一半的鴨子不會飛,那就變成要逐一將不會飛的鴨子檢查並覆寫為 cout<<"cannot fly"<<endl;;若此時又出現第三種情形,cout<<"fly in space<<endl;,有好幾種鴨子屬於此類,那又得一一覆寫,不利於維護。
(皆用使用draw.io繪製)
https://ithelp.ithome.com.tw/upload/images/20220916/20140096BpfuwxulQZ.png
於是,本書的第一個原則出現了:

第一個原則

把會變和不會變的部分隔開

會變的部分封裝起來,就可以修改會變的部分,並不影響不變的部分。
回來看鴨子會變與不變的部分:

  • 會變: fly(), quack()(不是每隻鴨子都會有這些feature)
  • 不變: display() (所有鴨子都會有各自的外觀)

然後,將會變的部分都抽出來到另外的類別中,達到「封裝」的效果,讓它不會影響其餘的部分。
這樣的話,結構就會變成"duck"一類,飛行行為與鳴叫行為各自一類。
此時可以暫停一下,自行想想這樣結構要怎麼設計比較好呢?

應用新原則的鴨子UML

https://ithelp.ithome.com.tw/upload/images/20220916/20140096pUf2SlOhwv.png
上半部是目前覺得可以合理使用繼承的部分(display),下面則是這幾隻鴨子各自飛行跟鳴叫行為,這個diagram可以怎麼長呢?
明天再繼續看下去,出現了第二個原則,還有策略模式給出的答案,跟自己的設計比較看看,也比較會有記憶點!


上一篇
[Day 2] 前置準備─ OO與UML
下一篇
[Day 4] 策略模式 (2)
系列文
設計模式探索30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言