1 回答

TA貢獻1725條經驗 獲得超8個贊
恐怕沒有通用的萬能的神奇答案——這完全取決于“幾乎”部分以及推動代碼中這些部分發(fā)生變化的力量。IOW,只能用一個具體的例子來回答......
話雖如此,從經驗中吸取了一些教訓,這些教訓主要在著名的(但不幸的是經常被誤解的)GOF“設計模式”一書中進行了總結。如果您花時間先閱讀本書的第一部分,您就會明白目錄中的大多數(如果不是全部)模式都基于相同的原則:將變體與不變體分開。一旦你可以在你的代碼中區(qū)分一個和另一個(警告:這里有一個陷阱,初學者幾乎總是陷入其中),應用哪種模式通常是顯而易見的(有時你才意識到你在你之后使用了這個和那個模式重構了你的代碼)。
現在正如我所說,有一個陷阱:意外重復。僅僅因為兩段代碼看起來相似并不意味著它們是重復的——很多時候,它們現在只是“意外地”相似但會造成其中一種改變的力量大多是不相關的。如果您嘗試立即重構此代碼,您很快就會發(fā)現自己使“通用”案例變得越來越復雜,以支持實際上不相關的更改,最終導致過于復雜、難以理解的混亂,只會使您的代碼無法維護。所以這里的訣竅是仔細檢查整個上下文,問問自己什么會推動一個或其他“相似”部分發(fā)生變化,如果有疑問,等到你知道更多。如果它發(fā)生比每次更改 A 時都必須出于完全相同的原因在 B 中進行完全相同的更改,那么您確實有真正的重復。
對于基于我們可以從您過于抽象的示例(和經驗)中猜測的更實用的短期建議,至少有兩種模式最常涉及在類層次結構中排除重復:模板方法和策略。
注意:我說“不幸的是經常被誤解”,因為大多數人似乎跳到模式目錄并試圖強制將它們全部放入他們的代碼中(無論它是否對手頭的問題有意義),并且通常通過復制粘貼規(guī)范教科書_實現_(通?;贘ava或C++)而不是理解_概念_并以既慣用又適應具體用例的方式實現它(例如:當函數是第一類對象時,你不一定需要一個Strategie類抽象基類和具體子類 - 最常見的是普通的舊回調函數 JustWork(tm))。
編輯完全不相關,但這個:
def __init__(self):
# initialize logging
logging.config.fileConfig(os.path.join(os.getcwd(),
'../myconfig.ini'))
self.logger = logging.getLogger(__name__)
不是如何使用日志記錄。庫代碼可以使用記錄器,但不能配置任何東西 - 這是應用程序(您的主腳本/函數/其他)的責任,合理的原因是正確的日志記錄配置取決于上下文 - 哪種類型的應用程序正在使用庫(a CLI 應用程序、本地 GUI 應用程序和后端 Web 應用程序根本沒有相同的需求)以及在哪種環(huán)境中(例如,本地開發(fā)環(huán)境需要比生產環(huán)境更多的日志)。
此外,使用__name__在您的基類模塊中創(chuàng)建的記錄器,所有子類都會將它們的日志發(fā)送到同一個記錄器,這當然不是您想要的(您希望它們擁有自己的包/模塊特定的記錄器,以便您可以微調每個包/模塊的配置)。
最后,這個:
os.path.join(os.getcwd(), '../myconfig.ini')
當然不會像您期望的那樣工作-此時您的 cwd 可以是任何東西,而您無法提前知道。如果要引用相對于當前文件目錄的路徑,則需要os.path.dirname(os.path.realpath(__file__)). 當然,在os.path.join()調用中添加系統特定的路徑內容(即“../”)完全破壞了使用os.path.
添加回答
舉報