Blog Cover Image

Inspire you to have New thinking, Walk out your unique Road.

有的時候,你無意間遇到的一些故事,會激發你的靈感,改變你的想法,接下來你會用與之前全然不同的觀念去創造屬於你獨特的故事。

Sign @MinaYu.

[後端 Junior] Python 之你的函式邏輯如何轉變為物件導向思維?

Posted on

就在我今天下午趁著公司沒網路,想說來畫一下程式邏輯或商業邏輯的架構圖,準備再來發文章。

但是,我們組的前端大大突然就來詢問我有關物件導向的事情,以及詢問我從函式的思維轉變為物件導向的思維是不是會痛苦一段時間?

我總不可能跟你說 不是 ,畢竟我當初從函式轉為使用物件時也是痛苦了一段時間,重點我第一次挑戰理解物件導向時,還失敗了

因為當時的技術能力不足以支撐我理解這個層面的邏輯,再加上網路上很多文章我看了也是有看沒有懂

對對對,請不要攻擊我先聽我娓娓道來!!!


是說恭喜我一下了,從一開始的後端小菜鳥,進化成後端 Junior, 但其實我目前的位置比較像是在 Mid-level ,不過物件的概念我應該也是在 Junior 階段了解的。


前言

我想大部分舉的例子都是 , , 或者 動物

嘿對沒錯,那是最簡單的例子,但是你要知道面對真正的專案時,可能是要面對比這些例子還困難幾倍的功能。

套一句我最近在看 設計模式 理解到的概念

為什麼要有物件導向的概念,物件的出現是為了讓程式更貼近生活。

因此你只要抱著這樣的概念去理解 物件導向,應該會比較容易理解(?)

對我來說,我認為物件的出現能有幾個優點:

  • 程式能夠比較容易被人閱讀
  • 修改, 重構, 新增功能時會比較容易

至於效能的問題,目前我還沒辦法鑽研這麼深入,這方面只能等待我之後去探討,再告訴大家了。

其實Python 這個語言,你要全用函式去撰寫功能其實也可以達到。

首先我們舉一個例子,來杯咖啡吧!

# 做一杯咖啡
def make_coffee(coffee_beas):
    # 準備水
    cold_water = prepare_water()
    # 煮沸水
    hot_water = cook_water(cold_water)
    # 放咖啡豆
    coffee_powder = put_coffee_beans(coffee_beans)
    # 做咖啡
    a_coffee = make(hot_water, coffee_powder)

其實函式就能夠實現 泡咖啡 這件事情了,函式就夠實現很多功能了,為什麼還需要物件?



物件導向概念

上方撰寫的函式符合 泡咖啡 的需求,那因為現在有咖啡機出現了,我們就直接交給咖啡機處理就可以了

待會公司高層要開會,我需要幫長官們準備咖啡,我眼前有三個咖啡機,我想我請這些咖啡機幫我泡咖啡就可以了

上面的函式已經有滿足泡咖啡的行為了,可是我今天想交給 咖啡機 做處理,並且依照不同的咖啡機煮不同的咖啡品種

因為不同主管喜歡不同的咖啡品牌,所以我們可以嘗試使用 物件導向來撰寫程式

所以在這個例子當中, 咖啡機 就是一個物件,那來看看我們可以怎麼實現這個場景


class CoffeeMachine(object):

    # 初始化咖啡機: 設想會有一個杯子可以泡咖啡,但是剛開始沒有水,所以先設定為 空陣列
    # 初始化咖啡機時就可以放一個品牌的咖啡豆,所以預設會放一個咖啡豆的品牌在咖啡機中
    def __init__(self, coffee_beans):
        self.cup = []
        self.beans = coffee_beans
    
    # 加水進杯子
    def put_water(self, water):
        self.cup.append(water)

    def cook_water(self):
        water = self.cup.pop(water)
        # ... 煮開水
        self.cup.append(hot_water)
    
    # 對,我不知道怎麼寫研磨,所以只好用中文命名函式了,千萬不要學 QQ
    def 研磨咖啡豆(self):
        # ... 研磨咖啡豆
        # 再把咖啡豆加進杯子中
        self.cup.append(self.beans)

    def make(self):
        # 泡咖啡
        return make_coffee(self.cup)


# 都備妥了,就開始做咖啡吧!!

# 一號咖啡機出動
# 初始化一台新的咖啡機,並放入巴西的咖啡豆
coffee_maker1 = CoffeeMachine("巴西的咖啡豆")

# 加入溫泉水
coffee_maker1.put_water("溫泉水")

# 煮沸溫泉水
coffee_maker1.cook_water()

# 研磨咖啡豆
coffee_maker1.研磨咖啡豆()

# 生出一碗咖啡 !!!
a_coffee = coffee_maker1.make()

# 二號開飛機出動
coffee_maker2 = CoffeeMachine("非洲的咖啡豆")
coffee_maker2.put_water("冷開水")
coffee_maker2.cook_water()
coffee_maker2.研磨咖啡豆()
a_coffee = coffee_maker2.make()

# 三號咖啡機出動
coffee_maker3 = CoffeeMachine("南美洲的咖啡豆")
coffee_maker3.put_water("自來水")
coffee_maker3.cook_water()
coffee_maker3.研磨咖啡豆()
a_coffee = coffee_maker3.make()

以物件導向的觀念設計咖啡機,並一樣一步驟一步驟的做出咖啡。

可是怎麼覺得好像很多行為都重複,我的手也很酸噎!!!

現在科技這麼進步,咖啡機也有自動化了吧?

所以我們來改善一下我們的咖啡機,為他加一個自動流程,讓你按一個按鍵就能先去做別的事,回來再來認領咖啡。


class CoffeeMachine(object):

    # 初始化咖啡機: 設想會有一個杯子可以泡咖啡,但是剛開始沒有水,所以先設定為 空陣列
    # 初始化咖啡機時就可以放一個品牌的咖啡豆,所以預設會放一個咖啡豆的品牌在咖啡機中
    def __init__(self, coffee_beans):
        self.cup = []
        self.beans = coffee_beans
    
    # 加水進杯子
    def put_water(self, water):
        self.cup.append(water)

    def cook_water(self):
        water = self.cup.pop(water)
        # ... 煮開水
        self.cup.append(hot_water)
    
    # 對,我不知道怎麼寫研磨,所以只好用中文命名函式了,千萬不要學 QQ
    def 研磨咖啡豆(self):
        # ... 研磨咖啡豆
        # 再把咖啡豆加進杯子中
        self.cup.append(self.beans)

    def make(self):
        # 泡咖啡
        self.cup = make_coffee(self.cup)
    
    def auto_flow(self, water):
        # 想像你現在在咖啡機裡面, self = 咖啡機本身
        # 這些功能都是咖啡機(self) 自動驅動各個功能來做咖啡
        self.put_water(self, water)
        self.cook_water()
        self.研磨咖啡豆()
        self.make()
        # 最後產出咖啡
        return self.cup


# 改良化咖啡機搞定了,再開始做咖啡吧!!

# 一號咖啡機出動
# 初始化一台新的咖啡機,並放入巴西的咖啡豆
coffee_maker1 = CoffeeMachine("巴西的咖啡豆")

# 倒入溫泉水然後點擊自動流程,咖啡機就自己運作啦!
a_coffee = coffee_maker1.auto_flow("溫泉水")

# 第二杯咖啡
coffee_maker2 = CoffeeMachine("非洲的咖啡豆")
a_coffee = coffee_maker2.auto_flow("冷開水")

# 第三杯咖啡
coffee_maker3 = CoffeeMachine("南美洲的咖啡豆")
a_coffee = coffee_maker3.auto_flow("自來水")

新增了自動化流程,是不是更貼近了人類的生活?

雖然對於剛開始理解物件導向的朋友們,物件的概念還是比函式稍稍的困難了些

不過多練習就會理解囉!



是說我剛剛想到另外一個例子,口好渴想要去自動販賣機買飲料來喝

販賣機 就是一個物件


# 嘿拍謝,我不知道自動販賣機的英文,讓我偷懶個XD
class 自動販賣機(object):

    def __init__(self):
        self.drinks = {1: "紅茶",
                       2: "冰咖啡",
                       3: "無糖綠茶"}
        self.coin = 0
    
    # 投幣給機器,他會累加,這樣就能知道這個販賣機一天能賺多少錢了!
    def put_coin(self, coin):
        self.coin += coin

    # 選飲料
    def choose_drink(self, number):
        drink = self.drinks.get(number)
        receipt = "發票"
        # 給發票跟飲料
        return receipt, drink
    

# 眼前又有三個飲料機,選擇第一台吧!
# 初始化一個新的自動販賣機
No1_drink_machine = 自動販賣機()

# 投幣20元
No1_drink_machine.put_coin(20)

# 取得發票跟1號飲料 (紅茶)
receipt, drink = No1_drink_machine.choose_drink(1)

臨時想的 飲料販賣機 點子,提供給大家玩玩看囉!



個人經驗談

上頭前言有說我第一次挑戰物件導向概念其實經驗是失敗的,當我才剛開始學會Python,並已經有用函式實現大部分的功能時,當時前輩告訴我可以開始使用物件導向的概念。

從本來函式思維轉成物件導向邏輯思維,真的痛苦了一陣子

我的第一個物件,是在研究了近兩三天的情況下矇懞懂懂的寫出來,剛開始我完全不懂 __init__ 的含義,跟他奮鬥了一陣子。

不過學到一半前輩就離職了,所以我後來的專案也都還是用函式寫居多

如果沒有人推你一把,或者你自己不推自己一把,你就是會一直用舊的思維去思考

於是我就繼續用函式寫專案,直到半年後我離職,進新公司,新的主管逼迫我用物件導向的概念在時間還允許的狀況下學習並實作於專案

等等,時間並沒有允許喔,我可是在短短的兩週還三週,學會了物件運用, 繼承, 設計模式, 抽象設計模式 嗚嗚。

但也是這樣一逼,我現在已經是用物件撰寫專案了

另外,我想說的是,很多程式的概念跟邏輯,在你第一次讀或嘗試了解時,碰壁了或者怎麼樣都不了解,這時候也別氣餒,別難過也別慌張。

只要你還在程式這條路上,這些碰壁的概念未來一定還會再被你遇到

而且,充其量只是你現階段的技術知識並不足以支撐你了解你想了解的概念

就先放著他,放著放著,兩個月過去,搞不好就看懂了,半年過去,回頭看你已經理解了

這就有點像我一開始在看物件時,我會覺得說天阿我這輩子根本不可能學會,但我現在已經在看物件的設計模式,並且實作各種物件在專案上了

過陣子,我又開始哀嚎,天阿資料結構難爆了,這輩子根本不可能學會啊!!,但我今天下午才用連結串列解出一題 LeetCode 中等難度的題目

我想跟大家說

這輩子還很長呢!

啊不是啦,是

如果還是覺得不舒服的話,還是先用函式寫功能吧!!

喂喂!!!

各位親愛的後端工程師們加油啊!!

是說,真的沒辦法理解的話,也不用強行逼迫自己的腦袋一定要理解,因為逼不得。

這時候就必須把這些怎麼學怎麼看都理解不能的概念擺一旁,放個熱水撒個玫瑰花瓣,再來杯冰的焦糖奶茶微糖,犒賞一下自己工作整週的週五 happy night

然後出了浴室,回到床上搞不好就夢到你已經理解這些概念了呢!!!