1

コンストラクターパラメーターIActionLoggeractionLoggerを挿入したいのですが、他のパラメーターlargeBucket、smallBucket、およびamountToRetrieveがコンテキスト依存である必要があります(これが正しい用語かどうかはわかりません)。

質問:

これらのコンストラクターパラメーターを自動プロパティにして、IActionLogger actionLoggerパラメーターをコンストラクターに残す必要がありますか?

基本的に、計算はlargeBucket、smallBucket、amountToRetrieve変数に基づいて異なりますか?事前にいくつかの設定を行う必要があるため、これらの変数をコンストラクターに入れました。

public class BucketActionsHandler : IBucketActionsHandler
{
    private List<IAction> _actions = new List<IAction>();
    private Bucket _largeBucket;
    private Bucket _smallBucket;
    private IActionLogger _actionLogger;
    private int _amountToRetrieve;


    public BucketActionsHandler(Bucket largeBucket, Bucket smallBucket, int amountToRetrieve, IActionLogger actionLogger)
    {
        _largeBucket = largeBucket;
        _smallBucket = smallBucket;
        _amountToRetrieve = amountToRetrieve;
        _actionLogger = actionLogger;

        _actions.Add(new LastAction(largeBucket, smallBucket, amountToRetrieve));
        _actions.Add(new EmptySmallerBucketAction(largeBucket, smallBucket, amountToRetrieve));
        _actions.Add(new EmptyLargeBucketAction(largeBucket, smallBucket, amountToRetrieve));
        _actions.Add(new FillLargeBucketAction(largeBucket, smallBucket, amountToRetrieve));
        _actions.Add(new FillSmallBucketAction(largeBucket, smallBucket, amountToRetrieve));
        _actions.Add(new TransferToLargeBucketAction(largeBucket, smallBucket, amountToRetrieve));
        _actions.Add(new TransferToSmallBucketAction(largeBucket, smallBucket, amountToRetrieve));
    }

    private IAction GetNextAction()
    {
        foreach (var action in _actions)
        {
            if (action.SatisfiedCondition())
            {
                return action;
            }
        }
        return null;
    }

    public void CalculateSteps()
    {
        IAction nextAction;
        do
        {
            nextAction = GetNextAction();
            nextAction.Execute();
            if (nextAction == null)
            {
                throw new InvalidOperationException("No valid action available");
            }
        } while(!(nextAction is LastAction));
    }
}
4

2 に答える 2

2

これらのコンストラクターパラメーターを自動プロパティにする必要があります

いいえ、これにより、注入または作成後にこのサービスを変更できるようになります。これは悪いことです。サービスはステートレスである必要があるか、少なくとも内部状態の変更がアプリケーションの正確性に影響を与えないためです。サービスの状態を変更すると、アプリケーションコードはこのサービスを一時的なものにします(要求されるたびに新しいインスタンスを注入する必要があります)が、アプリケーションは気にしません。これにより、コンポジションルート(アプリケーションの起動パス)からライフタイムサービスの制御と決定が移動し、保守性が妨げられます。

代わりに、ファクトリを使用してください。

public interface IBucketActionsHandlerFactory
{
    IBucketActionsHandler Create(
        Bucket largeBucket,
        Bucket smallBucket,
        int amountToRetrieve);
}

このファクトリをそれを必要とするサービスに注入し、そのサービスに適切なコンテキスト変数を提供させることができます。

public class SomeService
{
    private IBucketActionsHandlerFactory factory;
    private IBucketRepository repository;

    public SomeService(IBucketActionsHandlerFactory factory,
        IBucketRepository repository)
    {
        this.factory = factory;
        this.repository = repository;
    }

    public void Handle(int amountToRetrieve)
    {
        var largeBucket = this.repository.GetById(LargeBucketId);
        var smallBucket = this.repository.GetById(SmallBucketId);

        var handler = this.factory.Create(largeBucket, smallBucket,
            amountToRetrieve);

        handler.CalculateSteps();
    }
}

工場は、新しいIBucketActionsHandler実装の作成を管理します。

public class BucketActionsHandlerFactory
    : IBucketActionsHandlerFactory
{
    private Container container;

    public class BucketActionsHandlerFactory(
        Container container)
    {
        this.container = container;
    }

    public IBucketActionsHandler Create(
        Bucket largeBucket, Bucket smallBucket,
        int amountToRetrieve)
    {
        return new BucketActionsHandler(
            largeBucket, smallBucket, amountToRetrieve,
            this.container.Get<IActionLogger>());
    }
}

あなたはCompositionRootBucketActionsHandlerFactoryの一部である必要があります。この場合、このファクトリにコンテナ/カーネルを注入することは問題ありません(これはDIインフラストラクチャの一部です)。

このようにして、アプリケーションは取得するハンドラーのタイプを認識しませんがBucketActionsHandler、現在のコンテキスト内で取得することはできます。

または、、、、および変数をメソッドlargeBucketに指定することもできます。これにより、工場への必要性を取り除くことができます。smallBucketamountToRetrieveCalculateSteps

public class BucketActionsContext
{
    public Bucket LargeBucket { get; set; }
    public Bucket SmallBucket { get; set; }
    public int AmountToRetrieve { get; set; }
}

public class BucketActionsHandler : IBucketActionsHandler
{
    private IActionLogger _actionLogger;

    public BucketActionsHandler(IActionLogger actionLogger)
    {
        _actionLogger = actionLogger;
    }

    public void CalculateSteps(
        BucketActionsContext context)
    {
        IAction nextAction;
        do
        {
            nextAction = this.GetNextAction(context);

            if (nextAction == null)
            {
                throw new InvalidOperationException(
                    "No valid action available");
            }

            nextAction.Execute();
        } 
        while(!(nextAction is LastAction));
    }

    private IAction GetNextAction(
        BucketActionsContext context)
    {
        return (
            from action in this.GetActions(context)
            where action.SatisfiedCondition()
            select action)
            .FirstOrDefault();
    }

    private IEnumerable<IAction> GetActions(
        BucketActionsContext context)
    {
        Bucket largeBucket = context.LargeBucket;
        Bucket smallBucket = context.SmallBucket;
        int amountToRetrieve = context.AmountToRetrieve;

        yield return new LastAction(largeBucket, smallBucket, amountToRetrieve);
        yield return new EmptySmallerBucketAction(largeBucket, smallBucket, amountToRetrieve);
        yield return new EmptyLargeBucketAction(largeBucket, smallBucket, amountToRetrieve);
        yield return new FillLargeBucketAction(largeBucket, smallBucket, amountToRetrieve);
        yield return new FillSmallBucketAction(largeBucket, smallBucket, amountToRetrieve);
        yield return new TransferToLargeBucketAction(largeBucket, smallBucket, amountToRetrieve);
        yield return new TransferToSmallBucketAction(largeBucket, smallBucket, amountToRetrieve);    
    }
}
于 2012-07-30T18:50:13.360 に答える
0

他のパラメーターを適切に渡しながら、手動で解決IActionLoggerしてコンストラクターに手動で注入する

、解決 時に依存性のオーバーライド(Unityでの呼び出し方法)を行うことができますBucketActionsHandler。これにより、渡された値を注入された依存関係として使用するように強制されます。

于 2012-07-30T18:30:39.153 に答える