2

次の設定を記述するデザインパターンはありますか?このデザインは大きな問題を抱えていますか? Widgetインスタンスは「ダム」コンストラクタWidget.__init__()することにより、または「インテリジェント」ファクトリメソッドWorkbench.upgrade_widget()のいずれかによって構築することができファクトリ関数での不変オブジェクトの変更

クラス:

class Widget: 
    def __init__(self, abc, def, ...): 
    self.abc = abc 
    self.def = def 
    ... 
    ... 

class Workbench: 

    # widget factory function, which uses data from the workbench instance 
    def upgrade_widget(self, widget, upgrade_info): 
    widget = Widget(widget.abc, widget.def, ...) 
    # I will modify the widget's attributes 
    ... 
    self.rearrange_widget(widget, xyz) # modifies widget's internal state 
    ... 
    widget.abc = ... # also modifies widget's state 
    ... 
    return widget 

    # uses data from the workbench instance 
    def rearrange_widget(self, widget, xyz): 
    ... 
    # this class does other stuff too 
    ... 

ウィジェットは、私は後にそのインスタンスを変更してはならないという意味で不変ですそれらは完全に初期化されています(多くのコードはこの不変量に​​依存します)。しかし、私はを変更すると、が初期化されていることが非常に便利で、コードをもっときれいにすることが分かりました。

私の主な関心事は、別のクラスの "不変"ウィジェットを変更することです。 upgrade_widgetにしか入っていなかった場合は、渡されたウィジェットを変更しないので、私はそれを使用している可能性があります。しかし、このメソッドは、引数として受け取ったウィジェットを変更する他のWorkbenchメソッド(rearrange_widget)に依存しています。この「不変」インスタンスが実際に変更できる場所を制御できなくなっているような気がします。誰かが間違いなくすでに完全に初期化されたウィジェットで偶然にrearrange_widgetと呼ぶことがあります。

+2

Python 2では常にクラスを「オブジェクト」から継承します。そうしないと、オブジェクトから継承しないクラスが古いスタイルクラスであるため、機能が不足し、誤動作を診断しにくくなる可能性があります。 – jsbueno

+0

申し訳ありませんが、Python 3 .... – max

答えて

1

ウィジェットの不変性を今どのように強化していますか?

あなたのウィジェットに「ロック」プロパティを追加し、そのプロパティを確認するようにSETATTRをラップする場合はどう:

class Widget(object): 
    __locked = False 
    def __init__(self,a,b,c,locked=True): 
     ... 
     self.__locked = locked 

    def lock(self): 
     self.__locked = True 

    def is_locked(self): 
     return self.__locked 

    def __setattr___(self,*args,**kw): 
     if self.__locked: 
      raise Exception('immutable') # define your own rather than use Exception 
     return super(Widget).__setattr__(self,*args,**kw) 

をその後、工場で:一般的な使用に

class Workbench(object): 
    def upgrade_widget(self,widget,upgrade_info): 
     widget = Widget(widget.a,widget.b,...,locked=False) 
     self.rearrange_widget(widget, blah) 
     widget.c = 1337 
     widget.lock() 
     return widget 

することができます一度それがロックされると、何も面白いことがクラスに起こらないことはかなり確実です。ウィジェットの不変性を気にするメソッドは、そのウィジェットのis_locked()もチェックする必要があります。たとえば、rearrange_widgetは、何もする前にウィジェットがロック解除されていることを確認する必要があります。

これは、インスタンスとの悪意のある不正行為にもかかわらず、とにかく起こる可能性があります。独自のメソッドによって属性が変更されるのを防ぐこともできません。

私が上に書いたコード(擬似パイソン)はテストされていませんが、うまくいけば、あなたの主な関心事にどう対処するのかという一般的な考え方を示していることに注意してください。

ああ、このパターンの特定の名前があるかどうかはわかりません。

+0

btw、私はこれをやったたびに、私は通常、独自のクラスのロックを実装し、それを継承する......クラスウィジェット(ロック可能):... – chees

1

@chees:それを行うの滑らかな印象の方法は__init____dict__を変更し、__setattr__は常に例外を発生させるようにすることです(raise Exceptionにところで、そのない良いアイデア - そのちょうど一般的に):

class Widget: 
    def __init__(self, args): 
     self.__dict__['args'] = args 

    def __setattr__(self, name, value): 
     raise TypeError 

また、Workbenchで同じ方法で変更する(つまり__dict__を使用する)ことは、あなたが実際にやってはならないことをあなたがしていることを常に思い出させています。

+0

は例外を発生させないことに同意します - あなた自身の例外を実装することができるように便宜のために書いています。効果)。私はdictを介して属性にアクセスすることは、多くのことをやらなければならない場合には少し難しいことですが、それはそれを良い阻害要因にしています。 – chees

+0

正確に。場合によっては、クラスの外部から二重下線付きのプライベート属性にアクセスするのではなく、実際にAPIを使用してはいけないことを思い出させるために、APIをドラッグしたいことがあります。 – aquavitae

関連する問題