軟體工程筆記 | method chaining / fluent interface 讓你的代碼更容易理解和使用

2023/08/03閱讀時間約 8 分鐘

某次請 GPT 幫我把原本要作為訊息使用的代碼封裝起來,它也完美完成
但意外的他給了我一個從沒看過的寫法
簡化後像是如下

from typing import Self

class MessageBuilder:
def __init__(self):
self.message = ''

def add_line(self, line: str) -> Self:
self.message += line + '\n\n'

# why return self ??
return self

def build(self) -> str:
return self.message


我的疑問是為什麼明明我更改物件狀態,卻還是要回傳物件本身(self)呢?
研究後才知道是為了實現 fluent interface(流暢接口) 所以使用 method chaining (方法鏈) 的形式來設計

這種模式可以使代碼更具可讀性,並使其看起來更像自然語言。

舉個例子

例如,以下是使用 `add_line` 的典型用法:

message_builder = MessageBuilder()
(
message_builder
.add_line("line 1")
.add_line("line 2")
.add_line("line 3")
)


但如果 `add_line` 不返回 `self`,那麼每次調用 `add_line` 方法都需要單獨的一行代碼:

message_builder = MessageBuilder()
message_builder.add_line("line 1")
message_builder.add_line("line 2")
message_builder.add_line("line 3")


雖然兩者做相同的是,但是讀起來的流暢程度和優雅程度就有點差別了
這就是使用 fluent interface (返回 self )的好處。

補充

方法鏈(Method Chaining)

方法鏈接是一個編程技巧,它允許對同一個對象進行多個操作調用,而不需要每次調用都引用該對象。通過方法鏈接,可以在同一條語句中鏈接多個方法調用。通常,每個方法調用返回對象的參考,使得可以繼續調用該對象的其他方法。

這個技巧通常讓程式碼變得更簡潔、更易讀。

方法鏈的好處:
1. 讓調用過程更接近自然語言。
2. 把原本參數列表複雜的方法化作多個參數列表簡單的方法來使用。
3. 減少不必要的代碼量。

這個三點都是有益於開發的,所以方法鏈的存在很有意義。

以上第二點再舉個更具體的例子:把原本參數列表複雜的方法化作多個參數列表簡單的方法來使用

沒有使用方法鏈

假設你有一個 Computer 類,你可以用一個方法來設置所有屬性:

class Computer:
def __init__(self, processor, memory, storage, graphics):
self.processor = processor
self.memory = memory
self.storage = storage
self.graphics = graphics

def specs(self):
return f"Processor: {self.processor}, Memory: {self.memory}, Storage: {self.storage}, Graphics: {self.graphics}"

my_computer = Computer('Intel i7', '16GB', '512GB SSD', 'NVIDIA GTX 1080')
print(my_computer.specs())


這個方法可能造成代碼難以閱讀和維護,特別是當參數變得更多或更複雜時。

使用方法鏈

你可以使用方法鏈,將每個設置拆分為獨立的方法:

class Computer:
def __init__(self):
self.processor = None
self.memory = None
self.storage = None
self.graphics = None

def set_processor(self, processor):
self.processor = processor
return self

def set_memory(self, memory):
self.memory = memory
return self

def set_storage(self, storage):
self.storage = storage
return self

def set_graphics(self, graphics):
self.graphics = graphics
return self

def specs(self):
return f"Processor: {self.processor}, Memory: {self.memory}, Storage: {self.storage}, Graphics: {self.graphics}"


my_computer = (
Computer()
.set_processor('Intel i7')
.set_memory('16GB')
.set_storage('512GB SSD')
.set_graphics('NVIDIA GTX 1080')
)
print(my_computer.specs())


Python 有可以指定參數的寫法,所以我覺得還好,但是當我用 Java 又要再 function 中傳入多個參數時候就有點痛苦了
不過同時也造成複雜度增加,我覺得還是要看情境使用,並不適合用在每個情況
如果你的 function 需要傳入那麼多參數,其實可以把他包成一個物件,或是看看是不是真的需要


限制:

方法鏈的一個限制是,只能用在不需要返回其他值的方法上,因為你需要返回self 對象。即使Python支持用一個return語句返回多個值,也可能無法解決這個問題。


流暢接口(Fluent Interface)

流暢接口是一種編程接口設計方法,使得對象的使用更符合自然語言的結構,提高了程式碼的可讀性和可維護性。流暢接口通常使用方法鏈接來實現。

流暢接口的目標是讓程式碼的讀者能夠更容易理解程式的功能。流暢接口通常用在建構器模式、查詢建立或任何你想以更描述性、自然的方式表示的地方。

總結

方法鏈接和流暢接口在許多現代編程語言和框架中都有使用。這兩個概念有時互相重疊,因為流暢接口通常使用方法鏈接來實現。使用這些技巧可以提高程式碼的可讀性和維護性,使得編碼更符合人類語言的結構。這對於在專案中協同工作的團隊尤為重要,因為它可以讓每個人更容易理解和使用代碼。

參考資料

對我來說 人生就是一個遊戲 活得開心,活得漂亮,活得成功,活得有意義 都是這場遊戲的一個個任務 我想要把這個遊戲打通關 在這裡我會分享一些我自己的經驗 把遊戲打通關的一些技巧 打通關的過程 和我自己發現的小 bug,或捷徑 遇到的喜怒哀樂 遇到的困難 遇到的挫折 歡迎大家一起來摸透和想受 這場人生遊戲
留言0
查看全部
發表第一個留言支持創作者!