在不破坏类结构的情况下对包含类中的操作进行矢量化

时间:2011-10-22 11:56:45

标签: c# design-patterns

我当前的项目被分成多个类,正确地表示了我们对系统中实体的看法。然而,这需要一个性能价格,所以我试图想出一种提高性能的方法,同时保持我们现有的类结构。

我认为一个例子最能说明问题:假设我有一个包含多个Order的{​​{1}}类。运送Item的天真实施正在发送其所有Order

Item

发送class Order { private List<Item> m_items; public void Ship() { foreach (Item item in m_items) { item.Ship(); } } } 是一个多阶段过程:

Item

事实证明,将class Item { public void Ship() { var receipt = m_boat.ShipToDestination(this); ProcessReceipt(receipt); } } 发送到Item需要很长时间。幸运的是,Boat可以同时发送多个BoatItem)。但是,要使用此方法,我必须重写List<Receipt> Boat.ShipToDestination(List<Item> items),如下所示:

Order.Ship()

这意味着class Order { public void Ship() { var receipts = m_boat.ShipToDestination(m_items); foreach (Receipt receipt in receipts) { ProcessReceipt(receipt); } } } 现在是ProcessReceipt(而不是Order)的一部分,并且Item不再负责其所有的运输物流。

在我的真实代码中,有许多方法可以解决这个问题,因此有效地使用此解决方案意味着大多数Item逻辑将进入Item类。然而,这似乎是错误的地方有这个逻辑 - 它应该在Order

我考虑过使用多个线程(例如,每Item使用一个Task),但这似乎太浪费了,特别是因为Item可以有几十个Order

我考虑的另一种方法是使用Items方法和QueuedBoat方法创建QueueForShipping(Item item)。现在ShipQueuedItems()可以致电OrderShipQueuedItems可以致电Item。这种方法的问题在于,在我的实际代码中,QueueForShipping仅在Receipt发布后返回,因此代码必须如下所示:

Item

这感觉它正朝着正确的方向发展(因为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)); } } 知道它有多少Order,它必须是知道何时一切都在Item上的组件,但是它将Boat分为两个阶段。在我的真实代码中,我有多个阶段(每个阶段可以单独矢量化),因此该方法将分为3-4个部分,这不是一个很好的视线。

有人可以提出一种向Ship进行矢量化的方法,同时将业务逻辑保留在Item.Ship()类中,或者我是否必须放弃订单/项目分离才能利用矢量化?

修改

另一种方法可能是:

Item

class Order { private List<Item> m_items; public void Ship() { for (int i = 0; i < m_items.Count; ++i) { bool isLast = (i == (m_items.Count - 1)); item.Ship(isLast); } } } class Item { public void Ship(bool isLast) { m_queuedBoat.QueueForShipping(this, FinalizeShipping); if (isLast) m_queuedBoat.ShipQueuedItems(); } private void FinalizeShipping(Receipt receipt) { ProcessReceipt(receipt); } } 类使用QueuedBoat为每个项调用回调。

1 个答案:

答案 0 :(得分:2)

嗯,无论如何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));
    }
}

所以Order可以是这样的:

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();
    }
}

该程序可以在运送过程中执行其他操作,即Order.PrepareShipping()Order.PerformShipping()之间(例如,也可以在同一条船上运送其他订单)。