6

作業中の単純なツール用の最初の DSL を作成しようとしています。ビルダー パターンを使用して複雑な親オブジェクトをセットアップしていますが、親オブジェクトの子コレクションを構築するためにレンガの壁にぶつかっています。サンプルは次のとおりです。

使用する:

var myMorningCoffee = Coffee.Make.WithCream().WithOuncesToServe(16);

クロージャー付きのサンプル(それが彼らの名前だと思います):

var myMorningCoffee = Coffee.Make.WithCream().PourIn( 
                        x => {
                                x.ShotOfExpresso.AtTemperature(100);
                                x.ShotOfExpresso.AtTemperature(100).OfPremiumType();
                             }
                        ).WithOuncesToServe(16);

サンプル クラス (子 PourIn() メソッドなしで、これは私が把握しようとしているものです。)

 public class Coffee
 {
   private bool _cream;

   public Coffee Make { get new Coffee(); }
   public Coffee WithCream()
   {
     _cream = true;
     return this;
   }
   public Coffee WithOuncesToServe(int ounces)
   {
     _ounces = ounces;
     return this;
   }
 }

したがって、仕事用のアプリでは、複雑なオブジェクトをうまく構築できますが、親オブジェクトのサブコレクション用にコード化されたラムダを取得する方法を一生理解できません。(この例では、expresso の shots (子コレクション) です)。

おそらく、ここで概念を混乱させているのでしょう。しかし、私はこれがどのように読めるかが本当に好きで、これを機能させる方法を理解したいと思っています.

ありがとう、サム

4

3 に答える 3

3

わかりましたので、追加の式ビルダーを使用して DSL を記述する方法を理解しました。これが私がDSLに読みたかった方法です:

var myPreferredCoffeeFromStarbucks =
            Coffee.Make.WithCream().PourIn(
                x =>
                    {
                        x.ShotOfExpresso().AtTemperature(100);
                        x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
                    }
                ).ACupSizeInOunces(16);

これが私の合格テストです:

[TestFixture]
public class CoffeeTests
{
    [Test]
    public void Can_Create_A_Caramel_Macchiato()
    {
        var myPreferredCoffeeFromStarbucks =
            Coffee.Make.WithCream().PourIn(
                x =>
                    {
                        x.ShotOfExpresso().AtTemperature(100);
                        x.ShotOfExpresso().AtTemperature(100).OfPremiumType();
                    }
                ).ACupSizeInOunces(16);

        Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Count == 2);
        Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == true);
        Assert.IsTrue(myPreferredCoffeeFromStarbucks.expressoExpressions[0].ExpressoShots.Dequeue().IsOfPremiumType == false);
        Assert.IsTrue(myPreferredCoffeeFromStarbucks.CupSizeInOunces.Equals(16));
    }
}

そして、これが私の CoffeeExpressionBuilder DSL クラスです。

public class Coffee
{
    public List<ExpressoExpressionBuilder> expressoExpressions { get; private set; }

    public bool HasCream { get; private set; }
    public int CupSizeInOunces { get; private set; }

    public static Coffee Make
    {
        get
        {
            var coffee = new Coffee
                             {
                                 expressoExpressions = new List<ExpressoExpressionBuilder>()
                             };

            return coffee;
        }
    }

    public Coffee WithCream()
    {
        HasCream = true;
        return this;
    }

    public Coffee ACupSizeInOunces(int ounces)
    {
        CupSizeInOunces = ounces;

        return this;
    }

    public Coffee PourIn(Action<ExpressoExpressionBuilder> action)
    {
        var expression = new ExpressoExpressionBuilder();
        action.Invoke(expression);
        expressoExpressions.Add(expression);

        return this;
    }

    }

public class ExpressoExpressionBuilder
{
    public readonly Queue<ExpressoExpression> ExpressoShots = 
        new Queue<ExpressoExpression>();

    public ExpressoExpressionBuilder ShotOfExpresso()
    {
        var shot = new ExpressoExpression();
        ExpressoShots.Enqueue(shot);

        return this;
    }

    public ExpressoExpressionBuilder AtTemperature(int temp)
    {
        var recentlyAddedShot = ExpressoShots.Peek();
        recentlyAddedShot.Temperature = temp;

        return this;
    }

    public ExpressoExpressionBuilder OfPremiumType()
    {
        var recentlyAddedShot = ExpressoShots.Peek();
        recentlyAddedShot.IsOfPremiumType = true;

        return this;
    }
}

public class ExpressoExpression
{
    public int Temperature { get; set; }
    public bool IsOfPremiumType { get; set; }

    public ExpressoExpression()
    {
        Temperature = 0;
        IsOfPremiumType = false;
    }
}

あらゆる提案を歓迎します。

于 2009-12-01T18:39:13.847 に答える
2

.IncludeApps が AppRegistrations の配列を受け入れたらどうなるか

IncludeApps(params IAppRegistration[] apps)

それから

public static class App
{
  public static IAppRegistration IncludeAppFor(AppType type)
  {
    return new AppRegistration(type);
  }
}

public class AppRegistration
{
  private AppType _type;
  private bool _cost;

  public AppRegistration(AppType type)
  {
    _type = type;
  }

  public AppRegistration AtNoCost()
  { 
    _cost = 0;
    return this;
  }
}

最終的にはこんな感じになるので…

.IncludeApps
(
  App.IncludeAppFor(AppType.Any), 
  App.IncludeAppFor(AppType.Any).AtNoCost()
)

IncludeApps メソッド内で、登録を検査し、必要に応じてオブジェクトを作成します。

于 2009-11-25T05:55:44.450 に答える
1

デリゲートルートに行くには、このようなものがうまくいくでしょうか?

var aPhone = MyPhone.Create;
  MyPhone.Create.IncludeApps
  (
    x =>
      {
        x.IncludeAppFor(new object());
      }
  );

class MyPhone
  {
    public MyPhone IncludeApps(Action<MyPhone> includeCommand)
    {
        includeCommand.Invoke(this);
        return this;
    }
  }

デリゲートルートに設定されていない場合、params が機能するでしょうか?

var anotherPhone = MyPhone.Create.IncludeApps(
    new IncludeAppClass(AppType.Math),
    new IncludeAppClass(AppType.Entertainment).AtNoCost());


class MyPhone
{
    internal MyPhone IncludeApps(params IncludeAppClass[] includeThese)
    {
        if (includeThese == null)
        {
            return this;
        }
        foreach (var item in includeThese)
        {
            this.Apps.Add(Item);
        }
        return this;
    }
}
于 2009-11-25T06:08:19.903 に答える