7

Addressを値オブジェクトとしてモデル化したいと思います。不変にするのは良い習慣なので、後で変更できる可能性のあるセッターを提供しないことにしました。

一般的なアプローチは、データをコンストラクターに渡すことです。ただし、値オブジェクトがかなり大きい場合、それはかなり肥大化する可能性があります。

class Address {
    public function __construct(
        Point $location,
        $houseNumber,
        $streetName,
        $postcode,
        $poBox,
        $city,
        $region,
        $country) {
        // ...
    }
}

別のアプローチは、引数を配列として提供することで、結果としてクリーンなコンストラクターになりますが、コンストラクターの実装を台無しにする可能性があります。

class Address {
    public function __construct(array $parts) {
        if (! isset($parts['location']) || ! $location instanceof Point) {
            throw new Exception('The location is required');
        }
        $this->location = $location;
        // ...
        if (isset($parts['poBox'])) {
            $this->poBox = $parts['poBox'];
        }
        // ...
    }
}

それも私には少し不自然に見えます。

かなり大きな値のオブジェクトを正しく実装する方法について何かアドバイスはありますか?

4

3 に答える 3

14

パラメーターの大きなリストの主な問題は、読みやすさと、パラメーターを混同する危険性です。効果的な Javaで説明されているように、Builder パターンを使用してこれらの問題に取り組むことができます。これにより、コードが読みやすくなります (特に、名前付きおよびオプションのパラメーターをサポートしていない言語)。

public class AddressBuilder {
    private Point _point;
    private String _houseNumber;

    // other parameters

    public AddressBuilder() {
    }

    public AddressBuilder WithPoint(Point point) {
        _point = point;
        return this;
    }

    public AddressBuilder WithHouseNumber(String houseNumber) {
        _houseNumber = houseNumber;
        return this;
    }

    public Address Build() {
        return new Address(_point, _houseNumber, ...);
    }
}

Address address = new AddressBuilder()
    .WithHouseNumber("123")
    .WithPoint(point)
    .Build();

利点:

  • パラメータは読みやすいように名前が付けられています
  • 番地と地域を混同しにくい
  • パラメータの独自の順序を使用できます
  • オプションのパラメータは省略可能

私が考えることができる1つの欠点は、コンストラクターを使用するときにコンパイル時エラーではなく、引数の1つを指定するのを忘れると(WithHouseNumberたとえば、呼び出していない)、実行時エラーが発生することです。たとえば、PostalCode などの値オブジェクトをさらに使用することも検討する必要があります (文字列を渡すのとは対照的に)。

関連して、ビジネス要件によって、値オブジェクトの一部を変更する必要がある場合があります。たとえば、住所が最初に入力されたときに番地のつづりが間違っている可能性があり、今すぐ修正する必要があります。Address を不変オブジェクトとしてモデル化したため、setter はありません。この問題の解決策の 1 つは、アドレス値オブジェクトに「副作用のない関数」を導入することです。この関数は、新しい通りの名前を除いて、オブジェクト自体のコピーを返します。

public class Address {
    private readonly String _streetName;
    private readonly String _houseNumber;

    ... 

    public Address WithNewStreetName(String newStreetName) {
        // enforce street name rules (not null, format etc)

        return new Address(
            newStreetName
            // copy other members from this instance
            _houseNumber);
    }

    ... 
}
于 2011-09-13T17:15:35.053 に答える
-2

不変は同時計算に適しており、ブロッキングもロックもありません。不変は高性能と優れたスケーラビリティに適しています。

したがって、値オブジェクトは並行システムでより適切に実行でき、分散システムに含め、古い VO を新しい VO に置き換えます。更新の必要がないため、ブロックされません。

于 2011-10-18T09:05:31.003 に答える