iT邦幫忙

0

這樣的物件設計好嗎?

  • 分享至 

  • xImage

交接同事的程式,物件錯綜複雜彼此糾纏,看code非常痛苦。
其中最讓我頭痛的是 他先把一個base 屬性給初始值寫在 當第一次讀取get 屬性時,判斷對應private 變數是不是null,
當判斷是null當下 呼叫function撈資料,
很多屬性都是depend on 那組base屬性,先判斷 自己的私變數是不是空 再去讀取前面base 那組property,,再去做篩選 塞回的私變數,
程式一堆這種一連串相生的屬性,看code快瘋掉了,
不知道大家覺得 這樣的寫法正常嗎?
要怎麼翻寫比較好解讀跟維護

請諸位大神賜教

AI Fan iT邦新手 4 級 ‧ 2024-12-22 11:04:08 檢舉
以下是GPT的回答 :
這段代碼的設計方式確實可能讓人感到困惑,尤其是當多個屬性互相依賴時,這樣的設計會讓代碼的可讀性和可維護性大打折扣。讓我們來看看這個問題的核心並提出一些可能的改善建議。

目前的問題
1.依賴鏈過長:多個屬性依賴於其他屬性,並且需要依賴 getter 方法來進行懶加載(當 _base 為 null 時才去加載數據)。這樣會讓程式碼讀起來像是無窮無盡的依賴鏈,讓追蹤每個變數的來源變得困難。
2.性能問題:每次調用 getter 時,都要進行是否為 null 的判斷,並在必要時重新加載數據。這會造成不必要的性能開銷,尤其是在頻繁訪問這些屬性的情況下。
3..可讀性差:這樣的設計方式使得其他開發者理解和維護代碼變得更加困難,特別是當有多個相互依賴的屬性時。
改善建議
1.使用延遲加載(Lazy Loading): 考慮將懶加載的邏輯提取到專門的函數或方法中,而不是每次都放在 getter 裡進行判斷。這樣可以避免 getter 變得過於複雜,也能讓代碼更具可讀性。

例如:

python
複製程式碼
def get_base():
if self._base is None:
self._base = self.load_base_data() # 加載邏輯提取到這裡
return self._base
引入初始化方法: 若每個屬性都需要依賴於 _base 或其他屬性進行初始化,可以考慮在物件創建時進行一次性初始化。這樣可以避免每次都進行懶加載,提升性能。

例如:

python
複製程式碼
class MyClass:
def __init__(self):
self._base = self.load_base_data()
self._filterA = self.initialize_filterA()

def initialize_filterA(self):
return self._base.where(A='a')
2.分離關注點(Separation of Concerns): 如果一個屬性不僅負責懶加載數據,還要進行過濾操作,可以考慮將數據處理邏輯與對象的屬性分開。你可以創建單獨的數據服務層來處理數據加載和過濾邏輯,使得對象只關心持有數據而非操作數據。

例如,創建一個專門的 DataService 類來負責加載和過濾:

python
複製程式碼
class DataService:
def load_base_data(self):
# 加載邏輯
pass

def filter_data(self, base, filter_condition):
return base.where(filter_condition)

class MyClass:
def __init__(self, data_service):
self._data_service = data_service
self._base = None
self._filterA = None

def get_base(self):
if self._base is None:
self._base = self._data_service.load_base_data()
return self._base

def get_filterA(self):
if self._filterA is None:
self._filterA = self._data_service.filter_data(self.get_base(), 'A=a')
return self._filterA
3. 減少不必要的 getter 和 setter: 當 getter 和 setter 變得過於複雜時,可能是設計過度的信號。可以考慮簡化這些屬性,將它們移除,將邏輯封裝在方法中。這樣既能提升性能,也能讓代碼更直觀。

例如:

python
複製程式碼
def get_filterA(self):
if not self._filterA:
self._filterA = self._base.where(A='a')
return self._filterA
總結
這種複雜的屬性依賴設計確實會讓代碼變得難以理解和維護。你可以通過將懶加載邏輯提取為獨立方法、引入初始化流程、將數據處理邏輯從對象中分離出來,以及減少 getter 和 setter 的使用來提升代碼的可讀性和可維護性。這些改進將有助於減少代碼的複雜度,使未來的開發和維護更加簡單。
froce iT邦大師 1 級 ‧ 2024-12-24 09:08:02 檢舉
1. 你沒考慮到你同事是多久前開發的,或許當時這是沒辦法的辦法。
2. 要重寫的的話現在應該可以用重載,但C#我不熟。像python這種沒重載的遇到這種狀況的確是這樣處理的,只是python的話通常會放在init而不是第一次get這種時機,或許是記憶體考量吧,但通常會初始化物件就是為了用他,很少遇到初始化不去get的。
圖片
  直播研討會
0
zivzhong
iT邦研究生 4 級 ‧ 2024-12-22 16:28:07

長線成長還是可以多多想一下 design pattern :
https://skyyen999.gitbooks.io/-study-design-pattern-in-java/content/oodPrinciple.html

1

如果每次null後都是call同一個funtion,感覺還算單純就還好..久了也會成記憶
但如果裡面更錯綜複雜,那放在base就不優了,每次都找會到瘋掉XD

我自己也遇到很鳥的,一串SQL語法要兜15個funtion才完成...,看完都吐了
20年年資的上司:我不想看,我直接重寫
/images/emoticon/emoticon46.gif

1
YC
iT邦好手 1 級 ‧ 2024-12-23 13:24:54

你是指
惰性求值嗎?

你沒有給範例,不是很清楚有什麼問題。

0
kawa0710
iT邦研究生 5 級 ‧ 2024-12-23 18:00:12

猜原PO遇到的問題:那個物件是用來做【快取】。
可能是要確定快取裡有沒有資料,有就直接取用,沒才讀資料。

我不知道有哪些Design Pattern有哪些可以用,但我以往都宣告一個static變數並讓程式盡早將資料讀入...像是系統的「選單」。如果系統只RUN在單一Server且架構允許,放到Redis/Garnet使用也不難。

1
Yaowen
iT邦研究生 3 級 ‧ 2024-12-24 16:10:35

照這個方式寫
設計模式

我要發表回答

立即登入回答