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。すでに完全に初期化されているウィジェットを誰かが誤って呼び出して、災害につながる可能性があります。

4

2 に答える 2

1

@chees:それを行うためのより良い方法は、変更__dict____init____setattr__常に例外を発生させることです(ところで、それは良い考えではありませんraise Exception-それは一般的なことです):

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

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

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

于 2012-04-23T06:10:18.943 に答える
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 は、何かを行う前に、ウィジェットのロックも解除されていることを確認する必要があります。

これは、いずれにせよ発生する可能性があるインスタンスの悪意のある改ざんにもかかわらずです。また、独自のメソッドによって属性が変更されることも妨げません。

私が上に書いたコード (疑似 python) はテストされていないことに注意してください。

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

于 2012-04-23T04:50:46.087 に答える