2016-08-15 165 views
5

我遇到了一個難題。我想我應該知道如何解決這個問題 - 我對Python非常瞭解和經驗豐富 - 但我無法弄清楚。看起來我正在努力應該通過設計模式來解決這個問題,這個模式是工廠主題的變體,但我無法回想起它。 (在本文末尾,我提出了一個技術解決方案,但看起來似乎不合理)。我希望你發現這個討論本身有意思,但我期待聽到一些解決我的問題的建議。給定類A,B,C和D,我想限制B實例的創建方法爲A,C實例爲B的方法,而D爲C的方法 - 換句話說,實例爲B實例的工廠,B實例C實例的工廠,C實例D實例的工廠。 (我也希望D的每個實例存儲哪個C實例創建它,C的每個實例存儲哪個B實例創建它,每個實例B存儲哪個實例A創建它,但這很容易當它在層次結構中創建下一個類的實例時,每個實例都將自身提供爲__init__參數。)如何在Python中將一個類的對象創建爲另一個類的實例?

這些是應用程序操作的模型層類。應用程序操作B,C或D的實例沒有問題,它不應該直接創建它們 - 它應該能夠直接創建A實例(並且A甚至可以是單例實例)。有多種驗證,管理,跟蹤,審計等等,這些都可以在創建下一個實例的一個類的方法中實現。

一個示例可能是一個操作系統,它可以創建可創建可創建文件的目錄的文件系統,但應用程序代碼必須遵循該鏈。例如,即使它在Directory中有它的手,它也不應該能夠創建Directory給Directory實例的文件,即使在被要求創建一個文件時這是Directory的實例會做什麼。

我正在尋找一種支持某些實現的設計解決方案,而不是用戶驗證 - 我瞭解後者的無用功能。

到目前爲止,我已經想到的唯一的事情是:

  1. 僅從情況下,_C()只的B實例開頭的所有類的名稱除A以下劃線
  2. 訪問_B()和_D()只從_C實例
  3. 依靠應用層程序員通過尊重該佈置和直接創建只(可能singleton)的A類

模塊級「隱藏」的實例從模塊的__all__列表中省略該類是不夠的,因爲它隻影響import *構造 - 另一個模塊仍然可以通過import module達到該類,然後參考module.class。 (這一切都隱約讓人聯想到C++的問題,它需要兩個類成爲朋友,因爲他們參與雙向關係:每個類的實例必須能夠引用另一個類的方法,關係的另一面)

可能最符合Python的語義和語用的解決方案是在C中定義D,在B中定義D,在A中定義B。這看起來是一種非常醜陋的方式將多個模塊的代碼集成到一個非常大的類中。 (想象一下,如果連鎖店再下降幾個級別。)這是嵌套類的更常見用法的延伸,也許是唯一技術上可行的方法,但我從來沒有見過這種俄羅斯娃娃類結構。

想法?

+0

這將是有益的,如果你能在你從自己的思路和範例的分離單句簡潔制定的問題。 – noumenal

+0

這很可怕,但不是嘗試使類構造函數無法訪問,您可以在構建過程中使用類似於[此處](http://stackoverflow.com/a/9812105/3895264)中描述的技術來檢查調用方法的類。請注意,我會推薦這個! – FujiApple

+0

分離是一個好主意 - 抱歉,我沒有想到它。 –

回答

6

Python是不是很擅長隱藏完全它的對象... 即使如果你決定做了「俄羅斯套娃」關閉試圖隱藏類定義,用戶仍然可以得到它... ...

class A(object): 
    def create_b(self): 
     class B(object): 
      pass 
     return B() 

a = A() 
b = a.create_b() 
b_cls = type(b) 
another_b = b_cls() 

簡而言之 - 如果用戶訪問源代碼(他們可以通過inspect得到它,或在最起碼,他們可以通過dis其中一個訓練有素的眼睛是不夠好,讓字節碼)那麼如果他們有足夠的動力,他們就有能力創建自己班級的實例。一般來說,將類記錄爲用戶不應該實例化的東西已經足夠了 - 如果他們違反了這種信任,那麼當程序崩潰並且被燒傷時(他們有一些令人不快的副作用)導致其電腦在清除硬盤驅動器後發生火災)。這是一個非常中央的Python哲學,在python mail archives中很好地聲明:

python中沒有什麼是真正的私有的。 沒有任何課堂或班級實例可以讓你遠離所有內在的東西(這使得自省 可能和強大)。 Python相信你。它說:「嘿,如果你想 在黑暗的地方四處張望,我會相信你有 是一個很好的理由,你沒有製造麻煩。」

畢竟,我們都在這裏同意大人。

C++和Java沒有這個哲學(不是相同的程度)。 它們允許您創建私有方法和靜態成員。

Perl文化在這方面與python相似,但Perl表達了對情感有點不同的感受。正如駱駝書所說的那樣,

「一個Perl模塊寧願你呆在它的客廳 因爲你沒有被邀請,不是因爲它有獵槍。」

但情緒是相同的。

1

只是從我的頭頂:

def B(object): 
    pass 

def D(object): 
    pass 

def bound(object): 
    if type(object) is C: 
     assert isinstance(D) 
    if type(object) is A: 
     assert isinstance(B) 
    else: 
     assert false 

@bound 
def C(D): 
    pass 

@bound 
def A(B): 
    pass 
+0

這段代碼需要測試:目前它不運行。闡明它背後的想法也是非常有用的。 – EOL

相關問題