3

これは主に思考実験です。これはすべてサンプルコードです。私の目標は、仕様パターンを使用して、ファクトリ内の条件付きコードの巨大なブロックを排除することでした。したがって、このサンプルには、適切な IStatusUpdate の実装を取得する StatusData オブジェクトがあります。

次の一連のテストがあります。

    [TestMethod]
    public void Factory_Interface_Should_Return_IStatusUpdate()
    {
      var factory = MockRepository.GenerateMock<IUpdateFactory<StatusData>>();
      var obj = MockRepository.GenerateStub<IStatusUpdate>();

      var data = new StatusData();
      factory.Stub(x => x.Get(data)).Return(obj);

      var item = factory.Get(data);

      Assert.IsInstanceOfType(item, typeof(IStatusUpdate));
    }

    [TestMethod]
    public void StatusUpdateFactory_Should_Return_IStatusUpdate()
    {
      var factory = new StatusUpdateFactory();
      var data = new StatusData();

      var item = factory.Get(data);

      Assert.IsInstanceOfType(item, typeof(IStatusUpdate));   
    }

    [TestMethod]
    public void StatusUpdateFactory_Should_Return_NewStatusUpdate_When_Status_Is_New()
    {
      var data = new StatusData(Status.New);
      var factory = new StatusUpdateFactory();

      var item = factory.Get(data);

      Assert.IsInstanceOfType(item, typeof(NewStatusUpdate));
    }

これまでの My Factory の実装は次のようになります。

public class StatusUpdateFactory:IUpdateFactory<StatusData>
  {
    public IStatusUpdate Get(StatusData item)
    {
      IList<ISpecification<StatusData>> specs = GetSpecifications();

      foreach (var spec in specs)
      {
        if (spec.IsSatisfiedBy(item))
          //how do I do this?
           return new NewStatusUpdate();

      }
      return null;
    }

    private IList<ISpecification<StatusData>> GetSpecifications()
    {
      var returnList = new List<ISpecification<StatusData>>();
      var specTypes = this.GetType().Assembly.GetTypes()
                        .Where(z => z.IsInstanceOfType(typeof(ISpecification<StatusData>)))
                        .ToList();


      specTypes.ForEach(x => returnList.Add(Activator.CreateInstance(x) as ISpecification<StatusData>));

      return returnList;

    }
  }

私が落ち込んでいるところは、ステータスオブジェクトによって満たされる仕様を発見した後、その仕様を IStatusUpdate を実装する型にどのようにマップするかということです..私は困惑しています.

IStatusUpdate 実装者への仕様のマッピングが必要であると誰かが正しく提案しました。このマッピングは工場の責任のようで、仕様から外れると SRP 違反の匂いがします。その責任を持つMapperクラスを作成することはできますが、それはあまり一般的ではないようで、マッパーを仕様にどのようにマップするかという疑問も生じます。

ここには、私が見逃している小さな飛躍がまだ 1 つあります。

4

2 に答える 2

3

私の理解が正しければ、ISpecification を実装するオブジェクトがあれば、IStatusUpdate を実装するオブジェクトが必要ですか?

あなたのサンプルでは、​​これらのタイプは定義されていないため、それらの間に使用できる関係があるかどうかはわかりません。

ただし、コードを保持するためのファクトリ、またはオブジェクトの作成を行うためのメソッド ISpecification.GetUpdate() が必要になる可能性があります。

于 2009-02-20T00:46:30.350 に答える
1

したがって、この一連の行に本当に焦点を合わせていると思います。

if (spec.IsSatisfiedBy(item))
          return new NewStatusUpdate();

そして、この現在の形式でこれを行う方法を尋ねていると思います。アイテムは次のようにサポートする必要があるようです

interface ISpecSupport<T>
{
    bool ItemSpecsContain(ISpecification<T> spec);
}

その後、spec.IsSatisfiedBy メソッドは、このインターフェイス タイプを受け取り、メソッドを実行できます。

言い換えれば、私はオブジェクトがそれが何であるかについての何らかの説明を(仕様に関して)持つべきだと言っていると思います。それはある種のリストだと思いますが、よくわかりません。おそらくこれについて考えたことがあると思いますので、何か追加できると助かります。

また、上記の代わりに、次のように並べ替えることができます。

if (item.Satisfies(spec))
    return new NewStatusUpdate();

こうすれば、非常に悪意のある訪問者パターンを使用する必要がなくなります (これは前に説明したことだと思います)。アイテムが仕様を所有しているように見えるため、より直接的です。このようにして、アイテムが仕様を満たしているかどうかを判断できるようになります。

このロジックをオブジェクト内に保持したくない場合 (これは理解できます) で、何らかのプロパティ バッグを使用している場合 (またはリフレクションが得意な場合) は、独立した仕様でオブジェクトの詳細を掘り下げることができます。バリデーター。実際、独立したバリデーターは最初から悪い考えではないかもしれません。仕様がアイテムと一致するかどうかを知る能力が、個々の仕様に残されるべき責任であるかどうかはわかりません.

于 2009-02-20T00:58:49.383 に答える