33

URL パラメータから mongodb のクエリを作成するのに役立つクエリ ビルダー クラスを作成しています。基本的な言語構造を使用したり、django の組み込みモデルを使用したりする以外に、オブジェクト指向プログラミングを行ったり、自分以外の人が使用するクラスを設計したりしたことはありません。

だから私はこのQueryBuilderクラスを持っています

class QueryHelper():
    """
    Help abstract out the problem of querying over vastly
    different dataschemas.
    """

    def __init__(self, collection_name, field_name, params_dict):
        self.query_dict = {}
        self.params_dict = params_dict
        db = connection.get_db()
        self.collection = db[collection_name]

    def _build_query(self):
        # check params dict and build a mongo query
        pass

ここで、 mongoの関数に渡すために、 を_build_queryチェックして入力します。これを行う際に、辞書を返す必要があるかどうか、または単に変更する必要があるかどうかについて、絶対に正しいアプローチがあるかどうか疑問に思っていました。これは内部メソッドであるため、変更するだけで問題ないと思います。これにアプローチする正しい方法(pythonic)の方法はありますか?これはばかげているだけで、重要な設計上の決定ではありませんか? どんな助けでも大歓迎です。params_dictquery_dictfind()_build_queryself.query_dictself.query_dict

4

4 に答える 4

15

self.query_dictオブジェクト指向プログラミングの全体的な考え方は、メソッドがオブジェクトの状態を変更できるということなので、変更するのはまったく問題ありません。メソッドが終了した後、オブジェクトが一貫した状態にある限り、問題はありません。内部メソッドであるという事実_build_queryは重要ではありません。オブジェクトが作成されたときに、後で呼び出してクエリを作成_build_queryすることを選択できます。__init__

決定は主にテスト目的で重要です。テストの目的では、必ずしもオブジェクト全体の状態をテストする必要なしに、各メソッドを個別にテストすると便利です。ただし、この場合は適用されません。これは、内部メソッドについて話しているため、他のオブジェクトや他のコードではなく、そのメソッドをいつ呼び出すかをユーザーが決定するためです。

于 2012-06-13T14:49:10.627 に答える
13

値を返すと、すべての属性の変更を 1 か所で保持できるため、望ましい方法です ( __init__)。また、これにより、後でコードを拡張することが容易になります。サブクラスでオーバーライドしたい場合_build_query、オーバーライドするメソッドは値を返すだけでよく、設定する属性を知る必要はありません。次に例を示します。

class QueryHelper(object):
    def __init__(self, param, text):
        self._param = param
        self._query = self._build_query(text)

    def _build_query(self, text):
        return text + " and ham!"

class RefinedQueryHelper(QueryHelper):
    def _build_query(self, text):
        # no need to know how the query object is going to be used
        q = super(RefinedQueryHelper, self)._build_query()
        return q.replace("ham", "spam")

対「セッターバージョン」:

class QueryHelper(object):
    def __init__(self, param, text):
        self._param = param
        self._build_query(text)

    def _build_query(self, text):
        self._query = text + " and ham!"

class RefinedQueryHelper(QueryHelper):
    def _build_query(self, text):
        # what if we want to store the query in __query instead?
        # then we need to modify two classes...
        super(RefinedQueryHelper, self)._build_query()
        self._query = self._query.replace("ham", "spam")

属性を設定することを選択した場合は_set_query、わかりやすくするためにメソッドを呼び出すことができます。

于 2012-06-13T14:57:29.417 に答える
10

何かを返す場合は、 をお勧めしselfます。インスタンス メソッドからの戻りselfは、各戻り値で同じオブジェクトの別のメソッド呼び出しが可能になるため、メソッド チェーンに便利です。

foo.add_thing(x).add_thing(y).set_goal(42).execute()

これは、「流れるような」API と呼ばれることがあります。

ただし、Python では、 や などの不変型のメソッド チェーンは許可されintていますが、やstrなどの可変コンテナーのメソッドにはメソッド チェーンが提供されていません。それでも、多くの Python ライブラリには「流れるような」API があります。listset

欠点は、そのような API を使用するとデバッグが難しくなる可能性があることです。ステートメント全体を実行するか、まったく実行しないため、ステートメント内の中間点でオブジェクトを簡単に確認できません。もちろん、私は通常、printPython コードをデバッグするのに完全に適していると思うので、print興味のある戻り値を持つメソッドに a を投げるだけです!

于 2012-06-13T15:00:38.407 に答える
6

オブジェクトのメソッドがその状態を直接変更するのは一般的ですが、オブジェクトが独自の「クライアント」になり、(通常は) プライベート アクセス メソッドを介して間接的にオブジェクト自体にアクセスすることが有利な場合があります。property()Python では、組み込みのクラス/関数を使用してこれを簡単に行うことができます。

これを行うと、カプセル化が向上し、それに伴う利点が得られます (実装の詳細からの分離が主なものです)。ただし、追加のコードが必要になりすぎて、多くの場合遅くなり、パフォーマンスに許容できない量の悪影響を与える可能性があるため、実際的ではない可能性があります。

于 2012-06-13T15:06:42.670 に答える