2009-12-18 4 views
2

Так у меня есть класс менеджера заказа, который выглядит как:Помощь проектирование заказа менеджер класс

public class OrderManager 
{ 
    private IDBFactory _dbFactory; 
    private Order _order; 

    public OrderManager(IDBFactory dbFactory) 
    { 
     _dbFactory = dbFactory; 
    } 


    public void Calculate() 
    { 

      _order.SubTotal 
      _order.ShippingTotal 
      _order.TaxTotal 

      _order.GrandTotal 


    } 
} 

Теперь, дело здесь иметь гибкий/Testible дизайн. Я очень обеспокоен тем, что могу написать твердые модульные тесты вокруг этого метода Calculate.

соображения:

 1. Shipping has to be abstracted out, be loose coupled since the implementation of shipping could vary depending on USPS, UPS, fedex etc. (they have their own API's). 
    2. same goes with calculating tax 

Должен ли я просто создать налог и класс доставки менеджер, и имеют налог/доставки завод в конструкторе? (точно, как я разработал класс OrderManager)?

(единственное, что я могу придумать, с точки зрения того, что я «пропустил», - это IoC, но я не против этого и не нуждаюсь в этом дополнительном уровне абстракции в моем представлении).

+0

Хорошо написанный код легко проверить. Разделите свою функциональность на гранулированные компоненты, проверьте на этом уровне. Также проверите все это на концерте. Тестирующий код не должен выглядеть 100% элегантным. Тестеры работают вокруг реализаций, а не наоборот. Иногда есть компромисс, но поверьте мне - на реальном мире, на рынке программного обеспечения (большая часть рынка), тестирование уделяется второму приоритету (NASA делает все по-другому). Держите его простым, пока не возникнет необходимость в сложности. –

+1

На этот вопрос можно ответить только на многодневную дискуссию на доске. –

+0

@Jeff Sternal - Согласен - дает некоторые идеи, которые будут бросать на доску :) – CSharpAtl

ответ

1

Ну, вы уже двигаетесь к инъекции зависимостей в своем подходе, так почему бы вам не пойти на все свиноматки и не использовать какой-то контейнер IoC, чтобы справиться с этим для вас?

Да, если вы хотите, чтобы он выдержал, создайте для него отдельный класс. Если вы хотите по-настоящему модульно протестировать то, что осталось, отвлечь интерфейс и провести макет тестирования. Проблема в том, что чем больше вы абстрагируетесь таким образом, тем больше нужно делать сантехнику, и чем больше вы окажетесь, тем не менее, хотите использовать какую-то структуру IoC.

Вы предлагаете инъекцию конструктора, что является общим подходом. Вы также сталкиваетесь с вводом свойств (конструктор без параметров, вместо этого задайте свойства). И есть также структуры, которые просят вас реализовать интерфейс инициализации, который позволяет инфраструктуре IoC выполнять инициализацию для вас в вызове метода. Используйте то, с чем вы чувствуете себя наиболее комфортно.

+0

У меня нет полного понимания Ioc, prob. почему я не использую это, если честно! – mrblah

+0

Вкратце, то, что IoC будет делать для вас здесь, это предоставить вам какой-то контейнерный или контекстный класс, который затем может предоставить вам экземпляр вашего класса менеджера заказов, который уже установил (ввел) эти зависимости вы. Вам нужно только беспокоиться о том, что вам нужен OrderManager, контейнер IoC делает все остальное. Затем в тестовом сценарии вы можете просто создать новый OrderManager (вместо использования контейнера для его создания), а затем вместо этого ввести макетные объекты, чтобы иметь возможность протестировать OrderManager по отдельности (например, выполнить его тестирование). –

1

Я действительно думаю, что IOC поможет с санкционированием создания конкретных конкретных классов, но вам все равно нужно, чтобы ваш дизайн был таким, каким вы хотите. Я думаю, вам нужно абстрагироваться от доставки с помощью интерфейса, который вы можете реализовать с классом для каждого из ваших грузоотправителей (USPS, UPS, FEDEx и т. Д.) И может использовать класс Factory (ShippingManager) для передачи правильного ответа или зависят от МОК, чтобы сделать это за вас.

public interface IShipper 
{ 
//whatever goes into calculating shipping..... 
decimal CalculateShippingCost(GeoData geo, decimal packageWeight); 
} 

Вы также можете просто вводить в IShipper и конкретные классы ITaxer в ваш OrderManager и рассчитать метод просто вызывает в этих классах .... и может использовать МОК прекрасно справиться с этим.

+0

Я предполагаю, что я не совсем понимаю МОК, отсюда и избегаю этого. – mrblah

+0

Посмотрите на это: http://structuremap.sourceforge.net/Default.htm – CSharpAtl

+0

Вы понимаете Inversion Of Control? Классы, которые зависят от других объектов, они передаются вместо их создания внутри класса. Это упрощает изменение зависимостей, таких как зависимость уровня данных, для тестирования. – CSharpAtl

1

Только мысль:

Ваш метод Calculate() не принимает никаких параметров, не возвращая ничего и действуя на частных полях не так, как я бы это сделать. Я бы написал его как статический метод, который принимает некоторые числа, IShippingProvider и ITaxJurisdiction и возвращает общую сумму в долларах. Таким образом, у вас есть возможность кэшировать дорогие звонки в UPS и ваши налоговые таблицы, используя memoization.

Может быть, я предвзято отношусь к общедоступным методам, которые работают так. Они сожгли меня в прошлом, пытаясь связать с элементами управления, использовать генераторы кода и т. Д.

EDIT: что касается инъекции зависимостей/IOC, я не вижу необходимости. Для этого были созданы интерфейсы. Вы не собираетесь загружать целые массивные дурацкие классы, просто некоторые реализации одного и того же веса/кода zipcode.

Вот что я бы сказал, если бы я был вашим начальником.

0

Я бы взял метод Calculate в класс. В зависимости от ваших обстоятельств OrderCalculator может потребоваться знать НДС, Валюту, Скидки, ...

Просто подумайте.

Смежные вопросы