1

私は次のようなコンストラクタを持っています:

public function __construct($data)
{
    $this->_data = new SimpleXMLElement($data);
}

それは結構です。ただし、simplexmlelement または文字列を渡す機会を与えたいと思います。

何かのようなもの:

public function __construct($data)
{
    if (is_string($data)) {
        $data = new SimpleXMLElement($data);
    }
    $this->_data = $data;
}

これは悪い習慣ですか?

私の考えでは、クライアント コードは前もってどのくらいの作業を行うかを決定できます。しかし、それは何か問題を引き起こしますか?

4

1 に答える 1

6

これに対処する 1 つの方法は、問題をそこから移動することです。実際には非常に簡単です。

public function __construct(SimpleXMLElement $data)
{
    $this->_data = $data;
}

次に、そこに SimpleXMLElement を渡すだけで、オブジェクトが文字列からのものか、別の SimpleXMLElement からのものか、またはそうでないものかをいつ構築するかを決定できます。

ご覧のとおり、これによりコードがさらに柔軟になります。次の 2 つの簡単なルールに従います。

  • newコンストラクター内でキーワードを使用しないようにします。
  • の使用を減らしますif

オブジェクトを作成するためのコードをどこに配置すればよいか迷っている場合 (たとえば、複数の場所で使用するロジックがあり、それを複製するのが怖い場合)、いくつかの静的ヘルパー メソッドを追加することを検討できます。

public static function createFromXmlString($string) {
    return static::createFromSimpleXmlElement(
        simplexml_load_string($string)
    );
}

public static function createFromSimpleXmlElement(SimpleXMLElement $element) {
    return new static($element);
}

public function __construct(SimpleXMLElement $data)
{
    ...

使用法:

$foo = foo::createFromXmlString('<root/>');

または、ジョブを実行するファクトリ オブジェクトを作成します (オブジェクト作成コードをオブジェクトから移動します)。

多くの場合、静的グローバル クラス メソッドは簡単に導入できるため、通常はその場で記述できますが、ほとんどの場合、2 つ以上ある場合は、コードをファクトリに移動するなど、それらの関数を再度削除する方法を検討し始めます。


これは[複数の入力タイプを扱うコンストラクター]の悪い習慣ですか?

newコンストラクター内でキーワードを使用するためです。それはテストを破棄し、後で使用するクラス名newは隠された依存関係です (それらは必要ありません。「オブジェクト コンストラクター内で新しいオブジェクトをインスタンス化する」のも参照してください。 [実際にはそれほど良い Q&A ではありません。コードの匂いを探してくださいこれについての議論と、制御の反転/依存性注入 --更新:この種の資料については、私の心の中にあります: Flaw: Constructor does Real Work (ca. Nov 2008; by Miško Hevery) (Whatch this guy on Youtube のビデオも) 、彼は物事を説明するための良いアクセントと良いスタイルを持っています)])

悪い習慣のもう 1 つの部分は、同じコンストラクターで処理するケースをどんどん追加する傾向があることです。そのため、実際にはオブジェクトは実際には変化していませんが、時間の経過とともに変化します。

これはよくある間違い (そして近道でもあります) だと思います. すでにここで尋ねているのは良い兆候だと思います.あなたは自分の感覚を研ぎ澄まし始めています.

私の考えでは、クライアント コードは前もってどのくらいの作業を行うかを決定できます。しかし、それは何か問題を引き起こしますか?

まず第一に、「クライアント」コードとオブジェクト コードが異なることは非常によく理解されています。メリットだと思うことを明確に示します。

一方、1 つのオブジェクトは一度に 1 つのことを行う必要があり、新しいオブジェクトの作成も重要なフェーズです。コンストラクターに多くのコードとロジックを入れ始めると、事態が複雑になる傾向があります。複雑なコードを導入するにはあまりにも重要な場所です (たとえば、3 行以上は複雑です)。コンストラクターは新しいオブジェクトのみを初期化する必要があり、それだけです。

私の回答の最初の部分で与えられた提案に関係なく、より多くの OOP スタイルはおそらく次のようになります。

abstract class Foo {...}

class FooString extends Foo {
    public function __construct($string) {
        ...
    }
}

class FooSimpleXML extends Foo {
    public function __construct(SimpleXMLElement $element) {
        ...
    }
}

あなたは1つのタイプ/オブジェクトを持っていますFoo. コードベースが大きくなるにつれて、クライアント コードにはFoofrom を取得するためのさまざまな要件がありますが、常にFoo. ベースタイプのサブタイプを作成することによりFoo、古いコードを変更してはならず、変更された要件に合わせて新しいコードを追加できます。

これはおそらく最もクリーンなアプローチですが、これは特殊Fooな型であり、ヘルパー オブジェクトの一種ではないことを知っておく必要があります。

于 2013-08-28T19:44:00.520 に答える