1

かなり複雑なオブジェクトを表すクラスがあります。オブジェクトは、インクリメンタルビルド、さまざまな形式のテキスト文字列の解析、バイナリファイルの分析など、さまざまな方法で作成できます。これまでの私の戦略は次のとおりです。

  • コンストラクター(__init__私の場合は)にすべての内部変数を初期化してもらいますNone

  • オブジェクトにデータを入力するためのさまざまなメンバー関数を提供します

  • これらの関数に、変更された新しいオブジェクトを呼び出し元に返してもらいます。sd = SuperDuper().fromString(s)

例えば:

class SuperDuper:
    def __init__(self):
        self.var1 = None
        self.var2 = None
        self.varN = None

    ## Generators
    def fromStringFormat1(self, s):
        #parse the string
        return self 
    def fromStringFormat2(self, s):
        #parse the string
        return self
    def fromAnotherLogic(self, *params):
        #parse params
        return self
    ## Modifiers (for incremental work)
    def addThis(self, p):
        pass
    def addThat(self, p):
        pass
    def removeTheOtherOne(self, p):
        pass

問題は、クラスが非常に大きくなることです。残念ながら、私はOOPパターンの設計に精通していませんが、この問題にはもっとエレガントな解決策があると思います。ジェネレーター関数をクラスから除外していますか(それは良い考えにfromString(self, s)なりますか?superDuperFromString(s)

4

4 に答える 4

3

あなたの場合、より良い考えは、依存性の注入と制御の反転です。アイデアは、これらのさまざまなソースすべてから解析しているすべての設定を持つ別のクラスを作成することです。次に、サブクラスは実際に解析するメソッドを定義できます。次に、クラスをインスタンス化するときに、設定クラスのインスタンスをクラスに渡します。

class Settings(object):
    var1 = None
    var2 = None
    var3 = None

    def configure_superduper(self, superduper):
        superduper.var1 = self.var1
        # etc

class FromString(Settings):
    def __init__(self, string):
        #parse strings and set var1, etc.

class SuperDuper(object):
    def __init__(self, settings): # dependency injection  
        settings.configure_superduper(self)  # inversion of control
        # other initialization stuff

sup = SuperDuper(object, FromString(some_string))

このようにすることには、クラスには変更する理由が1つだけ(発生する可能性が高い)であるという単一責任の原則をより厳密に遵守するという利点があります。これらの文字列の保存方法を変更した場合は、クラスを変更する必要があります。ここでは、データソースごとに1つの単純な個別のクラスに分離しています。

一方、保存されているデータが保存されている方法よりも変更される可能性が高いと思われる場合は、Ignacioが提案しているように、クラスメソッドを使用することをお勧めします。これは(少し)複雑で、実際にはそうではないためです。その場合、このスキームで2つのクラスを変更する必要があるため、多くを購入します。もちろん、もう1つ割り当てを変更するだけでよいので、それほど害はありません。

于 2010-10-14T08:02:47.070 に答える
2

それらはすべてクラスに直接関係しているので、そうなるとは思いません。

がすることは、コンストラクターに引数をとらせてフィールドを初期化し(Noneもちろんデフォルトで)、次にすべてのfrom*()メソッドを新しいオブジェクトを構築して返すクラスメソッドに変換します。

于 2010-10-14T07:56:42.937 に答える
1

クラス内に変換/作成メソッドがあるのは悪い設計ではないと思います。いつでも別のクラスに移動して、非常に軽量なデザインパターンであるSimpleFactoryを作成できます。

私はそれらをクラスに残しておきます:)

于 2010-10-14T08:02:26.813 に答える
1

これらの関数に、変更された新しいオブジェクトを呼び出し元に返してもらいます。sd = SuperDuper().fromString(s)

これが良い考えになることはめったにありません。一部のPythonライブラリクラスはこれを実行しますが、これは最善のアプローチではありません。

一般的に、これを実行します。

class SuperDuper( object ):
    def __init__(self, var1=None, var2=None, var3=None):
        self.var1 = var1
        self.var2 = var2
        self.varN = var3

    def addThis(self, p):
        pass
    def addThat(self, p):
        pass
    def removeTheOtherOne(self, p):
        pass

class ParseString( object ):
    def __init__( self, someString ):
        pass
    def superDuper( self ): 
        pass

class ParseString_Format1( ParseString ):
    pass

class ParseString_Format2( ParseString ):
    pass

def parse_format1( string ):
    parser= ParseString_Format1( string )
    return parser.superDuper()

def parse_format2( string ):
    parser= ParseString_Format2( string )
    return parser.superDuper()

def fromAnotherLogic( **kw ):
    return SuperDuper( **kw )

オブジェクトとオブジェクトの文字列表現の2つの無関係な責任 があります。

オブジェクトと文字列表現を混同しないでください。

オブジェクトと解析は別々に保つ必要があります。結局のところ、コンパイラは生成されるコードの一部ではありません。XMLパーサーとドキュメントオブジェクトモデルは、通常、別々のオブジェクトです。

于 2010-10-14T10:10:34.080 に答える