1

ここにダウンロードリンクがあり ます https://skydrive.live.com/redir.aspx?cid=c565323a2a3927de&page=self&resid=C565323A2A3927DE!234&parid=C565323A2A3927DE!119&authkey=!Av1VEdfY3hmpl14&Bpub=SDX.SkyDrive&Bsrc=Share

だから私はこのようなドメインモデルを持っています。

public enum ItemType
{
    TypeA,
    TypeB
}    

public class Item
{
    public int ID;
    public ItemType Type;
    public ItemServiceFactory Factory = new ItemServiceFactory();

    public IItemService ItemService { get; set; } 

    public Item(ItemType type )
    {
        ItemService = Factory.GetItemService(type);
        Type = type;
    }

    public ItemValue GetValue()
    {
        return ItemService.GetValue(this);
    }

}

public interface IItemService
{
    ItemValue GetValue(Item item);
}

public class ItemServiceA : IItemService
{
    private readonly WebServiceA _webServiceA = new WebServiceA();

    public ItemValue GetValue(Item item)
    {
        return new ItemValue(_webServiceA.GetValuesA(new List<int> { item.ID }).FirstOrDefault());
    }
}

public class ItemServiceB : IItemService
{
    private readonly WebServiceB _webServiceB = new WebServiceB();

    public ItemValue GetValue(Item item)
    {
        return new ItemValue(_webServiceB.GetValuesB(new List<int> { item.ID }).FirstOrDefault());
    }
}

public class ItemServiceFactory
{
    public IItemService GetItemService(ItemType type)
    {
        switch (type)
        {
            case ItemType.TypeA: return new ItemServiceA();
            case ItemType.TypeB: return new ItemServiceB();

            default: throw new ArgumentOutOfRangeException();
        }
    }
}

public class ItemValue
{
    public int Value;

    public ItemValue(int value)
    {
        Value = value;
    }
}

public class WebServiceB
{
    public IEnumerable<int> GetValuesB(IEnumerable<int> idList)
    {//call web service. dummy here.
        return idList.Select(x => x + 100);
    }
}

public class WebServiceA
{
    public IEnumerable<int> GetValuesA(IEnumerable<int> idList)
    {//call web service. dummy here.
        return idList.Select(x => x - 100);
    }
}



var tooManyItems = new List<Item>
    {
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),
        new Item(ItemType.TypeA),

        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB),
        new Item(ItemType.TypeB)
    };

    Console.WriteLine(tooManyItems.Select(x => x.GetValue().Value));//or whatever.

今、私はDDD(ドメイン駆動設計)に従っており、Itemクラスを保持して、その値を取得する方法を知りたいと思っています。現在のモデルでは、 Item クラスが初期化されると、 Itemtypeに基づいてItemServiceA/ItemServiceBが設定されます。ItemObj.GetValue() が呼び出されると、Item クラスは、使用する必要があるサービスを「認識」し、その後、このコードで、呼び出す Web サービスを認識します。

注: WebService は項目のリストの呼び出しをサポートしていますが、現在のモデルでは、常に 1 つの項目リストとしてのみ渡されます (すべての Item オブジェクトの GetValue() に対して)。

現在のコードの問題は、アイテムの長いリストがあり、すべてのアイテムの値が必要で、それらが Web サービスからのものである場合、これは非常に非効率的で遅いことです。

質問: この設計では、アイテムがその値を取得する方法を把握できるようにし、複数のアイテムの呼び出しを WebServiceA と WebServiceB への 2 つの異なる呼び出しにグループ化したいと考えています。何か案は?

ありがとう

4

3 に答える 3

1

わかりました、誰も質問に答えていないので、私はこれに対する私自身の解決策を投稿するつもりです. 私がしたことは、マルチスレッドのアプローチに基づいていました。Item::GetValue 呼び出しごとに新しいワーカー スレッドが作成されます。BatchItemService と呼ばれる新しいクラスを作成しました。このクラスの仕事は、これらの呼び出しをリッスンし、ロジックに基づいてグループ化した後、独自の呼び出しを行い、呼び出しが終了すると、実行が完了するまで待機中のスレッドに通知することです。スレッド数が何があっても正常に戻るようにするには、これに厳密なタイムアウト ポリシーを適用する必要があります。

ここにコードがあります

    private static IEnumerable<KeyValuePair<Item, ItemValue>> GetResultsAsync(IEnumerable<Item> tooManyItems)
{
    var returnResult = new List<KeyValuePair<Item, ItemValue>>();
    var threads = new List<Thread>();

    foreach (var thread in tooManyItems.Select(item => new Thread(() => returnResult.Add(new KeyValuePair<Item, ItemValue>(item, item.GetItemValue())))))
    {
        threads.Add(thread);
        thread.Start();
    }
    foreach (var thread in threads)
        thread.Join();

    return returnResult;
}


public class ItemServiceFactory
{
    private static BatchItemService _batchItemService;

    public IItemService GetItemService(ItemType type)
    {
        return _batchItemService ?? (_batchItemService = new BatchItemService());
    }
}



public class BatchItemService : IItemService
{
    private static readonly List<Item> ItemsToCall = new List<Item>();
    private static readonly List<KeyValuePair<Item, ItemValue>> ItemsCalled = new List<KeyValuePair<Item, ItemValue>>();
    private static readonly object LockAll = new object();
    private bool _defer;



    private readonly System.Timers.Timer _timer = new System.Timers.Timer(50);

    public BatchItemService()
    {
        _timer.Enabled = true;
        _timer.Elapsed += MakeConsolidatedWebServiceCall;
    }

    private void MakeConsolidatedWebServiceCall(object sender, ElapsedEventArgs e)
    {
        if (_defer)
        {
            return;
        }

        _defer = true;

        lock (LockAll)
        {
            if (ItemsToCall.Count != 0)
            {

                var ItemAItemsToCall = new List<Item>();
                var ItemBItemsToCall = new List<Item>();


                ItemAItemsToCall.AddRange(ItemsToCall.Where(x => x.Type == ItemType.ItemA));

                if (ItemAItemsToCall.Any())
                {
                    Console.WriteLine("calling ItemAWebService");
                    var ItemAMeaureResults =
                        (new ItemAWebService()).GetItemAResults(ItemAItemsToCall.Select(x => x.ID));
                    ItemsCalled.AddRange(ItemAMeaureResults.Zip(ItemAItemsToCall,
                                                                  (first, second) =>
                                                                  new KeyValuePair<Item, ItemValue>(second,
                                                                                                           new ItemValue
                                                                                                               (first))));
                }

                ItemBItemsToCall.AddRange(ItemsToCall.Where(x => x.Type == ItemType.ItemB));

                if (ItemBItemsToCall.Any())
                {
                    Console.WriteLine("calling ItemBWebService");
                    var ItemBItemValues = (new ItemBWebService()).GetItemBResults(ItemBItemsToCall.Select(x => x.ID));
                    ItemsCalled.AddRange(ItemBItemValues.Zip(ItemBItemsToCall,
                                                                  (first, second) =>
                                                                  new KeyValuePair<Item, ItemValue>(second,
                                                                                                           new ItemValue
                                                                                                               (first))));

                }

                foreach (var Item in ItemAItemsToCall.Concat(ItemBItemsToCall))
                {
                    ItemsToCall.Remove(Item);
                }
            }


            Monitor.PulseAll(LockAll);
            _defer = false;
        }
    }

    public ItemValue GetItemValue(Item Item)
    {
        ItemValue returnVal;

        lock (LockAll)
        {
            ItemsToCall.Add(Item);
        }

        lock (LockAll)
        {
            Monitor.Wait(LockAll);
            returnVal = ItemsCalled.FirstOrDefault(x => x.Key.ID.Equals(Item.ID)).Value;
            if (returnVal == null)
            {
                throw new ApplicationException(" value cannot be null. sync issue ");
            }
            Console.WriteLine("received result for Item ID:" + returnVal.Value);
            ItemsCalled.Remove(ItemsCalled.FirstOrDefault(x => x.Key.ID.Equals(Item.ID)));
        }

        return returnVal;
    }
}
于 2013-08-06T09:07:38.073 に答える