C# 在不破坏类结构的情况下对包含类中的操作进行矢量化
我当前的项目被分为多个类,这些类正确地表示了我们对系统中实体的看法。然而,这是以性能为代价的,所以我试图提出一种在保持现有的类结构的同时提高性能的方法 我认为一个例子最能说明这个问题:假设我有一个C# 在不破坏类结构的情况下对包含类中的操作进行矢量化,c#,design-patterns,C#,Design Patterns,我当前的项目被分为多个类,这些类正确地表示了我们对系统中实体的看法。然而,这是以性能为代价的,所以我试图提出一种在保持现有的类结构的同时提高性能的方法 我认为一个例子最能说明这个问题:假设我有一个Order类,它包含多个项s。运送订单的一个简单实现是运送其所有项目s: class Order { private List<Item> m_items; public void Ship() { foreach (Item item in m_
Order
类,它包含多个项
s。运送订单
的一个简单实现是运送其所有项目
s:
class Order
{
private List<Item> m_items;
public void Ship()
{
foreach (Item item in m_items)
{
item.Ship();
}
}
}
事实证明,在船上运送项目
需要很长时间。幸运的是,船
可以同时运送多个项目
(列出Boat.ShipToDestination(列出项目)
)。但是,要使用此方法,我必须重写Order.Ship()
,如下所示:
class Order
{
public void Ship()
{
var receipts = m_boat.ShipToDestination(m_items);
foreach (Receipt receipt in receipts)
{
ProcessReceipt(receipt);
}
}
}
这意味着处理收据
现在是订单
(而不是项目
)的一部分,而且项目
不再负责其所有运输物流
在我的实际代码中,有很多方法可以解决这个问题,因此有效地使用这个解决方案意味着大多数项
逻辑将进入顺序
类。然而,这似乎是一个错误的地方有这种逻辑-它真的应该在项目
我考虑过使用多个线程(例如,每个项目使用任务),但这似乎太浪费了,特别是因为订单
可以有几十个项目
我考虑的另一种方法是使用QueueForShipping(Item Item)
方法和ShipQueuedItems()
方法创建QueuedBoat
。现在,Order
可以调用ShipQueuedItems
,而Item
可以调用QueueForShipping
。这种方法的问题是,在我的真实代码中,收据
仅在项目
发货后返回,因此代码必须如下所示:
class Order
{
private List<Item> m_items;
public void Ship()
{
foreach (Item item in m_items)
{
item.Ship();
}
m_queuedBoat.ShipQueuedItems();
foreach (Item item in m_items)
{
item.FinalizeShipping();
}
}
}
class Item
{
public void Ship()
{
m_queuedBoat.QueueForShipping(this);
}
public void FinalizeShipping()
{
ProcessReceipt(m_queuedBoat.GetReceiptForItem(this));
}
}
当QueuedBoat
类使用其收据调用每个项目的回调时,无论如何Ship
是一种异步操作:必须同时运行多个项目。因此必须分为两个阶段:PrepareShipping
(作废)和PerformShipping
(等待实际发货完成并返回处理其收据)
我想这样说:
class Item
{
public void PrepareShiping()
{
m_queuedBoat.QueueForShipping(this);
}
public void PerformShipping()
{
m_queuedBoat.StartActualShippingIfNotAlreadyStarted();
m_queuedBoat.WaitForShippingEnd();
ProcessReceipt(m_queuedBoat.GetReceiptForItem(this));
}
}
class Order
{
public void PrepareShipping()
{
foreach (Item item in m_items)
item.PrepareShiping();
}
public void PerformShipping()
{
foreach (Item item in m_items)
item.PerformShipping();
}
// and for those who don't need asynchronity
public void Ship()
{
PrepareShipping();
PerformShipping();
}
}
所以顺序可以是这样的:
class Item
{
public void PrepareShiping()
{
m_queuedBoat.QueueForShipping(this);
}
public void PerformShipping()
{
m_queuedBoat.StartActualShippingIfNotAlreadyStarted();
m_queuedBoat.WaitForShippingEnd();
ProcessReceipt(m_queuedBoat.GetReceiptForItem(this));
}
}
class Order
{
public void PrepareShipping()
{
foreach (Item item in m_items)
item.PrepareShiping();
}
public void PerformShipping()
{
foreach (Item item in m_items)
item.PerformShipping();
}
// and for those who don't need asynchronity
public void Ship()
{
PrepareShipping();
PerformShipping();
}
}
程序可以在发货过程中执行其他操作,即在订单.PrepareShipping()
和订单.PerformShipping()
之间(例如,也可以在同一艘船上发货其他订单).在C#5中,它将更容易:人们将能够使发送任务并使用新的异步/等待技术异步启动它。(将名称从Begin/End更改为Prepare/Perform)这是一种有趣的方法。我喜欢它的地方在于它不需要Order
访问QueuedBoat
就可以开始发货。但是,它仍然需要我将Item.Ship
拆分为多个阶段(在人为示例中为两个阶段,在实际代码中为三个或四个阶段)。请注意,这里的一切都是同步的:将要发货的项目逐个排队,然后我们发货,然后我们处理收据。刚刚意识到“同时发货其他订单”的意思。这很有趣,因为这实际上是我们想到的向量化的下一个阶段:在同一艘船上从多个订单
s运送Item
s。telewin:嗯,你不能将Item.ship
作为一个操作,否则它会将整艘船作为一个项目,因为该项目不知道其他项目。应该有一个运输经理来处理这个问题,在我的代码中这是订单,它调用first PrepareShipping,并且只调用PerformShipping。@telewin:好的,我会将isLast重命名为shouldTriggerPerform
,并将其作为订单的参数。Ship
也:public void Ship(bool shouldTriggerPerform){for(int i=0;i