2

私は予約クラスを持つドメインモデルで作業しています:

class Reservation
{
    public function changeStatus($status) { ... }
}

このchangeStatus()メソッドは、すべての適切な通知 (電子メールなど) が送信されるコンテキストでのみ呼び出す必要があるため、このメソッドの呼び出しを次のように制限したいと思いますReservationService

class ReservationService
{
    public function confirmReservation(Reservation $reservation)
    {
        $reservation->changeStatus(Reservation::STATUS_CONFIRMED);
        // commit changes to the db, send notifications, etc.
    }
}

私は PHP を使用しているため、パッケージの可視性フレンド クラスなどの概念はありません。そのため、私のchangeStatus()メソッドは単にパブリックであるため、アプリケーションのどこからでも呼び出すことができます。

この問題に対して私が見つけた唯一の解決策は、ある種の二重ディスパッチを使用することです:

class Reservation
{
    public function changeStatus(ReservationService $service)
    {
        $status = $service->getReservationStatus($this);
        $this->setStatus($status);
    }

    protected function setStatus($status) { ... }
}

潜在的な欠点は次のとおりです。

  • それは設計を少し複雑にします
  • それはエンティティにサービスを認識させますが、それが実際に欠点であるかどうかはわかりません

上記のソリューションについて何かコメントはありますか、またはこのchangeStatus()メソッドへのアクセスを制限するために提案するより良い設計はありますか?

4

4 に答える 4

4

必要なコンテキストを強制するインターフェースを使用します。

interface INotifiable {
  public function updated( $reservation );
}

class Reservation {
  public function changeStatus( $status, INotifiable $notifiable ){
    $this->setStatus( $status );
    $notifiable->updated( $this );
  }
}

class EmailNotifier implements INotifiable {
  public function updated( $reservation ){
    $this->sendUpdateEmail( $reservation ); //or whatever
  }
}

予約は、サービスについて何も知る必要はありません。別の方法として、Reservation でイベントを定義することもできますが、これにより複雑さが増し、おそらく必要のないものになります。

于 2011-11-08T12:25:39.097 に答える
1

あるドメイン エンティティから別のドメイン エンティティにメッセージを送信できます。特定のメッセージを生成できるオブジェクトのみが、問題のメソッドを呼び出します。コード スニペットを以下に示します。このソリューションは、ここPHP+DDDのような依存性注入が一種の宗教であるプロジェクト向けです。

予約サービスはメッセージ ファクトリを取得します。ファクトリは、コンストラクター メソッドを介して注入されます。このファクトリを持たないオブジェクトは、この種のメッセージを発行できません。(もちろん、オブジェクトのインスタンス化をファクトリに制限する必要があります。)

class Domain_ReservationService
{

    private $changeStatusRequestFactory;

    public function __construct(
        Message_Factory_ChangeStatusRequest $changeStatusRequestFactory
    ) {
        $this->changeStatusRequestFactory = $changeStatusRequestFactory;
    }

    public function confirmReservation(Domain_Reservation $reservation) {

        $changeStatusRequest = $changeStatusRequestFactory->make(
            Reservation::STATUS_CONFIRMED
        );

        $reservation->changeStatus($changeStatusRequest);
        // commit changes to the db, send notifications, etc.

    }

}

Reservation オブジェクトはメッセージの内容をチェックし、何をすべきかを決定します。

class Domain_Reservation
{

    public function changeStatus(
        Message_Item_ChangeStatusRequest $changeStatusRequest
    ) {
        $satus = $changeStatusRequest->getStatus();
        ...
    }

}

メッセージ オブジェクトは DDD 値オブジェクトです。(時にはそれは戦略のように機能します。)

class Message_Item_ChangeStatusRequest
{
    private $status;

    public function __construct( $status ) {
        $this->$status = $status;
    }

    public function getStatus() {
        return $this->$status;
    }

}

このファクトリはメッセージを生成します。

class Message_Factory_ChangeStatusRequest
{

    public function make($status) {
        return new Message_Item_ChangeStatusRequest ($status);
    }

}

すべてのドメイン オブジェクトは、このレイヤー ファクトリによって生成されます。

class Domain_Factory
{

    public function makeReservationService() {
        return new Domain_ReservationService(
            new Message_Factory_ChangeStatusRequest()
        );
    }

    public function makeReservation() {
        return new Domain_Reservation();
    }

}

上記のクラスは、次のようにアプリケーションで使用できます。

$factory = new Domain_Factory();
$reservationService = $factory->makeReservationService();
$reservation = $factory->makeReservation();
$reservationService->confirmReservation($reservation);

しかし、ステータス定数を渡す代わりに $reservation->beConfirmed() を使用したくない理由がわかりません。

于 2012-08-30T15:26:08.557 に答える
0

Symfony2 と FLOW3 フレームワークが採用したことの 1 つは、安定したパブリック API に@api注釈コメントをタグ付けすることです。

これはまさにあなたが探しているものではありませんが、それに近いものです。ユーザーが信頼できる API の部分を文書化します。さらに、エンティティはサービスについて知る必要がなく、悪循環依存を回避できます。

例:

class Request
{
    /**
     * Gets the Session.
     *
     * @return Session|null The session
     *
     * @api
     */
    public function getSession()
    {
        return $this->session;
    }
}
于 2011-11-08T12:21:33.597 に答える