Недавно пробовал для компании "х". Они прислали мне несколько вопросов и сказали, что нужно решить только один.
Проблема такая -
Базовый налог с продаж применяется по ставке 10% на все товары, за исключением книг, продуктов питания и медицинских изделий, которые не облагаются налогом.
Ввозная пошлина - это дополнительный налог с продаж, применяемый ко всем импортируемым товарам по ставке 5% без каких-либо исключений.
Когда я покупаю товары, я получаю квитанцию, в которой указаны названия всех товаров и их цена (включая налоги), в конце указана общая стоимость товаров и общая сумма уплаченных налогов с продаж.
Правила округления для налога с продаж заключаются в том, что для ставки налога n% полочная цена p содержит (np / 100, округленное до ближайших 0,05) сумму налога с продаж.
«Они сказали мне, что им интересен аспект дизайна вашего решения, и они хотели бы оценить мои навыки объектно-ориентированного программирования ».
Это то, что они рассказали своими словами
- В качестве решения мы хотели бы, чтобы вы использовали Java, Ruby или C #.
- Нас интересует ДИЗАЙН-АСПЕКТ вашего решения, и мы хотели бы оценить ваши навыки объектно-ориентированного программирования .
- Вы можете использовать внешние библиотеки или инструменты для создания или тестирования. В частности, вы можете использовать библиотеки модульного тестирования или инструменты сборки, доступные для выбранного вами языка (например, JUnit, Ant, NUnit, NAnt, Test :: Unit, Rake и т. Д.)
- При желании вы также можете включить краткое объяснение вашего дизайна и предположений вместе с вашим кодом.
- Обратите внимание, что мы НЕ ожидаем веб-приложения или всеобъемлющего пользовательского интерфейса. Скорее, мы ожидаем простого консольного приложения и заинтересованы в вашем исходном коде.
Итак, я предоставил код ниже - вы можете просто скопировать код вставки и запустить в VS.
class Program
{
static void Main(string[] args)
{
try
{
double totalBill = 0, salesTax = 0;
List<Product> productList = getProductList();
foreach (Product prod in productList)
{
double tax = prod.ComputeSalesTax();
salesTax += tax;
totalBill += tax + (prod.Quantity * prod.ProductPrice);
Console.WriteLine(string.Format("Item = {0} : Quantity = {1} : Price = {2} : Tax = {3}", prod.ProductName, prod.Quantity, prod.ProductPrice + tax, tax));
}
Console.WriteLine("Total Tax : " + salesTax);
Console.WriteLine("Total Bill : " + totalBill);
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
Console.ReadLine();
}
private static List<Product> getProductList()
{
List<Product> lstProducts = new List<Product>();
//input 1
lstProducts.Add(new Product("Book", 12.49, 1, ProductType.ExemptedProduct, false));
lstProducts.Add(new Product("Music CD", 14.99, 1, ProductType.TaxPaidProduct, false));
lstProducts.Add(new Product("Chocolate Bar", .85, 1, ProductType.ExemptedProduct, false));
//input 2
//lstProducts.Add(new Product("Imported Chocolate", 10, 1, ProductType.ExemptedProduct,true));
//lstProducts.Add(new Product("Imported Perfume", 47.50, 1, ProductType.TaxPaidProduct,true));
//input 3
//lstProducts.Add(new Product("Imported Perfume", 27.99, 1, ProductType.TaxPaidProduct,true));
//lstProducts.Add(new Product("Perfume", 18.99, 1, ProductType.TaxPaidProduct,false));
//lstProducts.Add(new Product("Headache Pills", 9.75, 1, ProductType.ExemptedProduct,false));
//lstProducts.Add(new Product("Imported Chocolate", 11.25, 1, ProductType.ExemptedProduct,true));
return lstProducts;
}
}
public enum ProductType
{
ExemptedProduct=1,
TaxPaidProduct=2,
//ImportedProduct=3
}
class Product
{
private ProductType _typeOfProduct = ProductType.TaxPaidProduct;
private string _productName = string.Empty;
private double _productPrice;
private int _quantity;
private bool _isImportedProduct = false;
public string ProductName { get { return _productName; } }
public double ProductPrice { get { return _productPrice; } }
public int Quantity { get { return _quantity; } }
public Product(string productName, double productPrice,int quantity, ProductType type, bool isImportedProduct)
{
_productName = productName;
_productPrice = productPrice;
_quantity = quantity;
_typeOfProduct = type;
_isImportedProduct = isImportedProduct;
}
public double ComputeSalesTax()
{
double tax = 0;
if(_isImportedProduct) //charge 5% tax directly
tax+=_productPrice*.05;
switch (_typeOfProduct)
{
case ProductType.ExemptedProduct: break;
case ProductType.TaxPaidProduct:
tax += _productPrice * .10;
break;
}
return Math.Round(tax, 2);
//round result before returning
}
}
вы можете отключить ввод и запустить его для разных вводов.
Я предложил решение, но мне отказали.
«Они сказали, что не могут рассматривать меня по нашим текущим открытым вакансиям, потому что кодовое решение не является удовлетворительным».
Пожалуйста, объясните мне, чего здесь не хватает. Разве это решение не является хорошим решением OOAD.
Как я могу улучшить свои навыки работы с OOAD.
Мои старшие тоже говорят, что идеальное приложение OOAD тоже практически не работает.
Спасибо
Ответы:
Во-первых, небеса, не делайте финансовых расчетов вдвое . Делайте финансовые расчеты в десятичном формате ; вот для чего это нужно. Используйте double для решения физических , а не финансовых проблем.
Главный недостаток вашей программы в том, что политика размещена не в том месте . Кто отвечает за расчет налогов? Вы поручили продукту рассчитывать налоги, но когда вы покупаете яблоко, книгу или стиральную машину, вещь , которую вы собираетесь купить , не отвечает за указание вам, сколько налогов вы собираетесь платить. Это. Правительственная политика обязана сообщить вам об этом. Ваш дизайн в значительной степени нарушает основной принцип объектно-ориентированного проектирования, согласно которому объекты должны нести ответственность за свои собственные проблемы , а не за чьи-либо еще. Задача стиральной машины - это стирать вашу одежду, а не взимать правильную импортную пошлину. Если изменится налоговое законодательство, вы не захотите его менятьобъект стиральной машины , вы хотите изменить объект политики .
Итак, как подойти к подобного рода проблемам в будущем?
Я бы начал с выделения каждого важного существительного в описании проблемы:
Итак, каковы отношения между всеми этими существительными?
... и так далее. Как только у вас будут определены все отношения между всеми существительными, вы можете приступить к проектированию иерархии классов. Есть абстрактный базовый класс Item. Книга наследует от нее. Есть абстрактный класс SalesTax; BasicSalesTax наследуется от него. И так далее.
источник
double
идеально подходит для ситуаций, когда более чем достаточно быть в пределах 0,00000001% от правильного ответа. Если вы хотите выяснить, с какой скоростью падает кирпич через полсекунды, вычислите дважды. Когда вы выполняете финансовую арифметику в двойном размере, вы получаете такие ответы, как например, цена после уплаты налогов составляет 43,79999999999999 долларов, и это выглядит глупо, хотя и очень близко к правильному ответу.Если компания скажет что-то о библиотеках вроде NUnit, JUnit или Test :: Unit, то более чем вероятно, что TDD им действительно импортирован. В вашем примере кода вообще нет тестов.
Я бы постарался продемонстрировать практические знания:
Я хотел бы порекомендовать www.dimecasts.net как впечатляющий источник бесплатных высококачественных скринкастов, охватывающих все вышеупомянутые темы.
источник
Это очень субъективно, но вот несколько замечаний по поводу вашего кода:
ИМХО вы перепутали
Product
иShoppingCartItem
.Product
должно содержать название продукта, налоговый статус и т. д., но не количество. Количество не является свойством продукта - оно будет разным для каждого клиента компании, который покупает этот конкретный продукт.ShoppingCartItem
должен иметьProduct
и количество. Таким образом, покупатель может свободно покупать более или менее один и тот же продукт. С вашей текущей настройкой это невозможно.Расчет окончательного налога также не должен быть частью
Product
- он должен быть частью чего-то вроде,ShoppingCart
поскольку окончательный расчет налога может включать в себя знание всех продуктов в корзине.источник
Прежде всего, это очень хороший вопрос для собеседования. Это хороший показатель многих навыков.
Там вы много вещей , которые вы должны понимать , чтобы обеспечить хороший ответ (нет нет идеального ответа), как высокого уровня и низкого уровня. Вот парочка:
Оттуда у вас может быть много интересных обсуждений, включая принципы проектирования (например, принципы SOLID), шаблоны проектирования, шаблоны анализа, моделирование предметной области, выбор технологий, пути будущего развития (например, что, если я добавлю базу данных или слой с расширенным пользовательским интерфейсом, что нужно изменить?), компромиссы, нефункциональные требования (производительность, ремонтопригодность, безопасность, ...), приемочные испытания и т. д.
Я не буду комментировать, как вам следует изменить свое решение, просто вам следует больше сосредоточиться на этих концепциях.
Но я могу показать вам, как я (частично) решил эту проблему , просто в качестве примера (на Java). Посмотрите в
Program
классе, как все это собрано вместе, чтобы распечатать эту квитанцию:Вам обязательно стоит взглянуть на эти книги :-)
В качестве предостережения: мое решение все еще очень неполное, я просто сосредоточился на сценарии счастливого пути, чтобы иметь хорошую основу для дальнейшего развития.
источник
Order
распечатывает квитанцию, ноReceipt
знает о собственном форматировании. Кроме того, TaxMethodPractice - это своего рода налоговая политика, она содержит все налоги, применимые к определенному сценарию. TaxMethods - это налоговые калькуляторы. Я чувствую, что вам не хватает только класса привязки более высокого уровня , такого как предлагаемый вами SalesEngine. Это интересная идея.За исключением того факта, что вы используете класс под названием product, вы не продемонстрировали, что знаете, что такое наследование, вы не создали множественное наследование классов от Product, никакого полиморфизма. Проблему можно было решить, используя несколько концепций ООП (даже чтобы показать, что вы их знаете). Это задача собеседования, поэтому вы хотите показать, как много вы знаете.
Однако сейчас я бы не впал в депрессию. Тот факт, что вы не продемонстрировали их здесь, не означает, что вы их еще не знаете или не можете их изучить.
Вам просто нужно немного больше опыта в ООП или интервью.
Удачи!
источник
Люди, которые начали изучать программирование с помощью ООП, не испытывают больших проблем, чтобы понять, что это означает, потому что это так же, как и в реальной жизни . Если у вас есть навыки программирования не только в объектно-ориентированном программировании, это может быть труднее понять.
Прежде всего, выключите экран или выйдите из любимой IDE. Возьмите бумагу и карандаш и составьте список сущностей , отношений , людей , машин , процессов , прочего и т. Д. Всего. что может встретиться в вашей окончательной программе.
Во-вторых, попытайтесь получить разные базовые сущности. Вы поймете, что некоторые могут иметь общие свойства или способности , вы должны поместить это в абстрактные объекты. . Вам следует начать рисовать красивую схему своей программы.
Затем вы должны указать функции (методы, функции, подпрограммы, называйте это как хотите): например, объект продукта не должен иметь возможность вычислять налог с продаж . Двигатель продаж должен.
Не испытывайте проблем со всеми громкими словами ( интерфейсы , свойства , полиморфизм , наследие и т. Д.) И шаблонами проектирования с первого раза, даже не пытайтесь создать красивый код или что-то еще ... Просто подумайте о простых объектах и взаимодействия между ними, как в реальной жизни .
После этого попробуйте прочитать серьезную и краткую литературу об этом. Я думаю, что Википедия и Викиучебники - действительно хороший способ начать, а потом просто читать о GoF, шаблонах проектирования и UML .
источник
Во-первых, не смешивайте
Product
класс с классом Receipt (ShoppingCart
), онquantity
должен быть частьюReceipItem
(ShoppingCartItem
), а такжеTax
&Cost
.TotalTax
ИTotalCost
должна быть частьюShoppingCart
.Мой
Product
класс имеет толькоName
&Price
& некоторые свойства , доступные только для чтения, напримерIsImported
:К вашей части расчета налогов прилагается
Product
. Продукт не определяет налоговую политику, это налоговые классы. Согласно описанию проблемы, существует два вида налогов с продаж:Basic
иDuty
налоги. Вы можете использоватьTemplate Method Design Pattern
для этого:И, наконец, класс для применения налогов:
Вы можете попробовать их на MyFiddle .
источник
Хорошей отправной точкой в правилах проектирования являются принципы SOLID .
Например, принцип Open Closed гласит, что если вы хотите добавить новую функциональность, вам не нужно добавлять код в существующий класс, а скорее добавлять новый класс.
Для вашего примера приложения это будет означать, что добавление нового налога с продаж потребует добавления нового класса. То же самое и с разными продуктами, которые являются исключениями из правил.
Очевидно, что правило округления относится к отдельному классу - принцип единой ответственности гласит, что каждый класс несет единственную ответственность.
Я думаю, что попытка написать код самостоятельно принесет гораздо больше пользы, чем просто написание хорошего решения и его вставка сюда.
Простой алгоритм написания идеально разработанной программы:
источник
Идеальная реализация ООП полностью спорна. Из того, что я вижу в вашем вопросе, вы можете модулировать код в зависимости от роли, которую они выполняют, для вычисления окончательной цены, такой как Product, Tax, ProductDB и так далее.
Product
может быть абстрактным классом, а производные типы, такие как Books, Food, могут быть унаследованы от него. Применимость налога может определяться производными типами. Продукт будет определять, применим ли налог, на основе производного класса.TaxCriteria
может быть перечислением, и это может быть указано во время покупки (импорт, применимость налога с продаж).Tax
класс будет рассчитывать налог на основеTaxCriteria
.Наличие
ShoppingCartItem
as, предложенного XXBBCC, может инкапсулировать экземпляры продукта и налога, и это отличный способ разделить детали продукта по количеству, общей цене с налогом и т. Д.Удачи.
источник
С точки зрения строго OOA / D, я вижу одну серьезную проблему, заключающуюся в том, что большинство ваших атрибутов класса имеют избыточное имя класса в имени атрибута. например, цена продукта , тип продукта . В этом случае везде, где вы используете этот класс, у вас будет излишне подробный и несколько запутанный код, например product.productName. Удалите из атрибутов избыточный префикс / суффикс имени класса.
Кроме того, я не видел никаких классов, связанных с покупкой и созданием квитанции, как было задано в вопросе.
источник
Вот отличный пример объектно-ориентированного шаблона для продуктов, налогов и т. Д. Обратите внимание на использование интерфейсов, которое очень важно в объектно-ориентированном дизайне.
http://www.dreamincode.net/forums/topic/185426-design-patterns-strategy/
источник
Решили проблему затрат с налогом, используя шаблон посетителя.
источник