Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Class 如何通过将多个web服务调用分组为一个来优化。设计模式c_Class_Oop_Design Patterns_Domain Driven Design - Fatal编程技术网

Class 如何通过将多个web服务调用分组为一个来优化。设计模式c

Class 如何通过将多个web服务调用分组为一个来优化。设计模式c,class,oop,design-patterns,domain-driven-design,Class,Oop,Design Patterns,Domain Driven Design,这是下载链接 我有一个这样的领域模型 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 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支持项目列表的调用,但在当前模型中,它始终仅作为一个项目列表传递

现在,当前代码中的问题是,如果我有一个很长的项目列表,并且我想要所有项目的值,并且它们来自某个Web服务,那么这是非常低效和缓慢的

问题:在这个设计中,我想让项目知道如何获得它的值,还想将多个项目的调用分组为对WebServiceA和WebServiceB的两个不同调用。有什么想法吗


谢谢

您出现问题的原因是您分配的班级职责不正确。具体来说,Item类有太多的职责——它除了自己的状态之外还包含工厂和服务。web服务遇到的问题是分布式计算中最常见的陷阱之一,这是一种假设,即可以像调用进程内代码一样调用网络绑定代码。要解决这些问题,请执行以下操作:

1使web服务调用在模型中显式。您的web服务类已经被设计为返回多个值,因此您应该让抽象接口具有相同的签名

2将调用服务的责任从Item类转移出去。这也将允许您摆脱工厂,在本例中,我将其称为服务定位器anti-patter。有时可以接受,但在这种情况下不行


3重新构造web服务抽象,使其能够为指定项的多个项返回值,而不仅仅是单个项类型。这样,您可以一次为多个项目调用它,并让抽象层担心要调用哪个实际的web服务。

出现问题的原因是您不正确地分配了类职责。具体来说,Item类有太多的职责——它除了自己的状态之外还包含工厂和服务。web服务遇到的问题是分布式计算中最常见的陷阱之一,这是一种假设,即可以像调用进程内代码一样调用网络绑定代码。要解决这些问题,请执行以下操作:

1使web服务调用在模型中显式。您的web服务类已经被设计为返回多个值,因此您应该让抽象接口具有相同的签名

2将调用服务的责任从Item类转移出去。这也将允许您摆脱工厂,在本例中,我将其称为服务定位器anti-patter。有时可以接受,但在这种情况下不行


3重新构造web服务抽象,使其能够为指定项的多个项返回值,而不仅仅是单个项类型。通过这种方式,您可以一次调用多个项目,并对调用哪个实际的web服务进行抽象处理。

好的,既然没有人回答这个问题,我将发布我自己的解决方案。 我所做的是基于多线程方法。每个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;
    }
}

好的,因为没有人回答这个问题,我将发布我自己的解决方案。 我所做的是基于多线程方法。每个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;
    }
}

我确实理解您试图做的事情:您有一个web服务,它接受项目列表并返回这些项目的值列表。但是您的域是以这样一种方式建模的,即您的客户机代码一次只能请求一个项/值。因为我不知道 你的应用程序是做什么的,或者你为什么这样设计它,我不能对此做出任何判断

尽管如此,旋转一个新线程来处理这个问题比使用线程池要贵一些,而且这并不是真的必要。我将更改您的GetResultsAsync方法,使其如下所示:

私有静态IEnumerable GetResultsAssociencenumerable tooManyItems{ var returnResult=新列表; Parallel.ForEachtooManyItems,item=>returnResult.Addnew KeyValuePairitem,item.GetItemResult; 返回结果; }
此实现使用线程池并完成您所追求的目标。

我确实理解您试图做的事情:您有一个web服务,它接受项目列表并返回这些项目的值列表。但是您的域是以这样一种方式建模的,即您的客户机代码一次只能请求一个项/值。因为我不知道你的应用程序是做什么的,也不知道你为什么要这样设计它,所以我不能对此做出任何判断

尽管如此,旋转一个新线程来处理这个问题比使用线程池要贵一些,而且这并不是真的必要。我将更改您的GetResultsAsync方法,使其如下所示:

私有静态IEnumerable GetResultsAssociencenumerable tooManyItems{ var returnResult=新列表; Parallel.ForEachtooManyItems,item=>returnResult.Addnew KeyValuePairitem,item.GetItemResult; 返回结果; }

此实现使用线程池并完成您的目标。

各位,请在问题仍在编辑时停止对其进行否决表决。每个人都足够成熟,知道我们需要保存草稿,以便在您遇到连接问题时保存工作。不,您不应该在线保存草稿。在你自己的电脑上保存草稿。我明白。我想把它存为草稿……找不到。这里有这样的功能吗?不过,我在msdn中已经多次这样做了。这更像是用户的否决票。StackOverflow应该添加更多的功能,比如为什么要投否决票。为什么这个问题会受到影响,社会也会因此受到影响。反对票会在评论中解释。我投了反对票,也不想解释原因,因为这对我来说是显而易见的。根本没有问题,没有解释,只有一堵代码墙。问题是用减价法写的,这是纯文本。如果您想要草稿,只需使用文本编辑器并脱机保存草稿即可。我认为不需要草稿,因为您可以在键入问题时实时查看格式化结果。当然可以。我会小心的。谢谢。各位,当问题还在编辑中时,请不要再投否决票了。每个人都足够成熟,知道我们需要保存草稿,以便在您遇到连接问题时保存工作。不,您不应该在线保存草稿。在你自己的电脑上保存草稿。我明白。我想把它存为草稿……找不到。这里有这样的功能吗?不过,我在msdn中已经多次这样做了。这更像是用户的否决票。StackOverflow应该添加更多的功能,比如为什么要投否决票。为什么这个问题会受到影响,社会也会因此受到影响。反对票会在评论中解释。我投了反对票,也不想解释原因,因为这对我来说是显而易见的。根本没有问题,没有解释,只有一堵代码墙。问题是用减价法写的,这是纯文本。如果您想要草稿,只需使用文本编辑器并脱机保存草稿即可。我认为不需要草稿,因为您可以在键入问题时实时查看格式化结果。当然可以。我会小心的。谢谢。您好,我建议不要使用您在这里编写的代码,因为您正在手动创建线程并调用线程。请加入以等待线程停止。手动创建线程比使用线程池要昂贵得多。在我提供一个代码示例来说明如何实现您所追求的目标之前,您使用的是.NET的哪个版本?您所说的是正确的。我最初尝试使用线程池。但这种方法的问题是,我打算调用的函数应该几乎在瞬间从所有对象调用。如果使用线程池,则只有活动线程调用该函数并等待,而其余线程甚至还没有启动。因此,在这种情况下,我无法进行任何优化。我尝试不同事情的全部原因是将多个http调用组合成一个调用,将尽可能多的调用分组。我使用的是4.0,更不用说ASP.NET,而不是WinForms。另外,我相信自己创建THRED并不坏,但不管理它们的生命周期才是。如果我选择积极的战略,THRED的数量很快就会上升,而且应该会很快下降。我用这些术语思考的另一个原因是即插即用的概念。我可以在不干扰域的情况下,用我们需要的任何函数插入那些需要的类。这只是一个问题,一行在注册在圣彼得堡
structuremap.here是下载链接您好,我建议不要使用您在此处编写的代码,因为您正在手动创建线程并调用Thread.Join,请等待线程停止。手动创建线程比使用线程池要昂贵得多。在我提供一个代码示例来说明如何实现您所追求的目标之前,您使用的是.NET的哪个版本?您所说的是正确的。我最初尝试使用线程池。但这种方法的问题是,我打算调用的函数应该几乎在瞬间从所有对象调用。如果使用线程池,则只有活动线程调用该函数并等待,而其余线程甚至还没有启动。因此,在这种情况下,我无法进行任何优化。我尝试不同事情的全部原因是将多个http调用组合成一个调用,将尽可能多的调用分组。我使用的是4.0,更不用说ASP.NET,而不是WinForms。另外,我相信自己创建THRED并不坏,但不管理它们的生命周期才是。如果我选择积极的战略,THRED的数量很快就会上升,而且应该会很快下降。我用这些术语思考的另一个原因是即插即用的概念。我可以在不干扰域的情况下,用我们需要的任何函数插入那些需要的类。这只是structuremap中注册表中的一行程序的问题