我有一組相關的類都從一個基類繼承。我想使用工廠方法爲這些類實例化對象。我想這樣做是因爲在將對象返回給調用者之前,我可以將這些對象存儲在由類名稱鍵入的字典中。然後,如果有一個特定類的對象的請求,我可以檢查是否已經存在於我的字典中。如果沒有,我將實例化它並將其添加到字典中。如果是這樣,那麼我會返回字典中的現有對象。這將基本上將我的模塊中的所有類轉換爲單例。Python - 我如何強制使用工廠方法來實例化對象?
我想這樣做,因爲他們都繼承的基類會自動包裝子類中的函數,而且我不希望函數被多次包裝,這就是目前發生的情況如果創建了兩個相同類的對象。
我可以考慮這樣做的唯一方法是檢查基類的__init__()
方法中的堆棧跟蹤,該方法將始終被調用,並在堆棧跟蹤未顯示請求進行調用時引發異常對象來自工廠功能。
這是個好主意嗎?
編輯:這裏是我的基類的源代碼。我被告知我需要找出元類來完成這個更優雅的事情,但這是我現在所擁有的。所有頁面對象使用相同的Selenium Webdriver實例,該實例位於頂部導入的驅動程序模塊中。該驅動程序初始化非常昂貴 - 它在首次創建LoginPage時進行初始化。初始化後,initialize()
方法將返回現有驅動程序,而不是創建新驅動程序。這個想法是,用戶必須先創建一個LoginPage。最終會有數十個Page類定義,並且它們將被單元測試代碼用來驗證網站的行爲是否正確。
from driver import get_driver, urlpath, initialize
from settings import urlpaths
class DriverPageMismatchException(Exception):
pass
class URLVerifyingPage(object):
# we add logic in __init__() to check the expected urlpath for the page
# against the urlpath that the driver is showing - we only want the page's
# methods to be invokable if the driver is actualy at the appropriate page.
# If the driver shows a different urlpath than the page is supposed to
# have, the method should throw a DriverPageMismatchException
def __init__(self):
self.driver = get_driver()
self._adjust_methods(self.__class__)
def _adjust_methods(self, cls):
for attr, val in cls.__dict__.iteritems():
if callable(val) and not attr.startswith("_"):
print "adjusting:"+str(attr)+" - "+str(val)
setattr(
cls,
attr,
self._add_wrapper_to_confirm_page_matches_driver(val)
)
for base in cls.__bases__:
if base.__name__ == 'URLVerifyingPage': break
self._adjust_methods(base)
def _add_wrapper_to_confirm_page_matches_driver(self, page_method):
def _wrapper(self, *args, **kwargs):
if urlpath() != urlpaths[self.__class__.__name__]:
raise DriverPageMismatchException(
"path is '"+urlpath()+
"' but '"+urlpaths[self.__class.__name__]+"' expected "+
"for "+self.__class.__name__
)
return page_method(self, *args, **kwargs)
return _wrapper
class LoginPage(URLVerifyingPage):
def __init__(self, username=username, password=password, baseurl="http://example.com/"):
self.username = username
self.password = password
self.driver = initialize(baseurl)
super(LoginPage, self).__init__()
def login(self):
driver.find_element_by_id("username").clear()
driver.find_element_by_id("username").send_keys(self.username)
driver.find_element_by_id("password").clear()
driver.find_element_by_id("password").send_keys(self.password)
driver.find_element_by_id("login_button").click()
return HomePage()
class HomePage(URLVerifyingPage):
def some_method(self):
...
return SomePage()
def many_more_methods(self):
...
return ManyMorePages()
這是如果一個頁面被實例化的時間屈指可數沒什麼大不了的 - 方法只會得到包裹的時間屈指可數和不必要的檢查,極少數會發生,但一切仍然可以工作。但是,如果一個頁面被實例化了幾十次,幾百次或幾萬次,那將會很糟糕。我只是把國旗在類定義爲每個頁面,並檢查是否這些方法已經被包裹着,但我喜歡保持類定義純淨搡所有的戲法到的深角落的想法我的系統,沒有人可以看到它,它只是工作。
你是一個實例工廠或類工廠後?你有沒有嘗試過一種相對簡單的類裝飾器方法? (我們可以看到你試過的東西,例如不起作用嗎?) –
讓我直截了當。你想把所有的類變成單例,因爲它們的基類被破壞了?聽起來就像拍攝你的狗,因爲一個瘋狂的屁股誰不斷闖入你的房子對狗過敏。 IOW是一個完全錯誤的「解決方案」。你確定你不想修復基類,或者至少解決它的缺陷? – delnan
@delnan我認爲線索是在標題:「我怎麼** **力......」 - 重點煤礦 –