Ostatnio starałem się o firmę „x”. Przysłali mi kilka pytań i kazali rozwiązać tylko jedno.
Problem jest taki -
Podstawowy podatek od sprzedaży wynosi 10% na wszystkie towary, z wyjątkiem książek, żywności i produktów medycznych, które są zwolnione.
Cło przywozowe to dodatkowy podatek od sprzedaży, który ma zastosowanie do wszystkich importowanych towarów i wynosi 5%, bez zwolnień.
Kiedy kupuję przedmioty, otrzymuję pokwitowanie, które zawiera nazwę wszystkich pozycji i ich cenę (wraz z podatkiem), kończąc na całkowitym koszcie towarów i łącznej kwocie zapłaconego podatku od sprzedaży.
Zasady zaokrąglania podatku od sprzedaży są takie, że dla stawki podatku n% cena półkowa p zawiera (np / 100 zaokrągloną w górę do najbliższej 0,05) kwotę podatku od sprzedaży.
„Powiedzieli mi, że są zainteresowani aspektem projektowym Twojego rozwiązania i chcieliby ocenić moje umiejętności programowania obiektowego ”.
Oto, co powiedzieli własnymi słowami
- Do rozwiązania chcielibyśmy, abyś użył języka Java, Ruby lub C #.
- Jesteśmy zainteresowani ASPEKTEM PROJEKTOWYM Twojego rozwiązania i chcielibyśmy ocenić Twoje umiejętności programowania obiektowego .
- Możesz używać zewnętrznych bibliotek lub narzędzi do celów budowania lub testowania. W szczególności możesz użyć bibliotek testów jednostkowych lub narzędzi do budowania dostępnych dla wybranego języka (np. JUnit, Ant, NUnit, NAnt, Test :: Unit, Rake itp.)
- Opcjonalnie możesz również dołączyć krótkie wyjaśnienie projektu i założeń wraz z kodem.
- Prosimy pamiętać, że NIE oczekujemy aplikacji internetowej ani wszechstronnego interfejsu użytkownika. Spodziewamy się raczej prostej, opartej na konsoli aplikacji i interesuje nas Twój kod źródłowy.
Więc podałem poniższy kod - możesz po prostu skopiować kod wklej i uruchomić w 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
}
}
możesz rozpakować wejście i uruchomić dla różnych wejść.
Podałem rozwiązanie, ale zostałem odrzucony.
„Powiedzieli, że nie mogą brać pod uwagę moich obecnych otwartych pozycji, ponieważ kod nie jest zadowalający”.
Proszę, prowadź mnie, czego tu brakuje. Czy to rozwiązanie nie jest dobrym rozwiązaniem OOAD.
Jak mogę poprawić swoje umiejętności OOAD.
Moi seniorzy również mówią, że idealna aplikacja OOAD również nie zadziała praktycznie.
Dzięki
Odpowiedzi:
Po pierwsze, niebiosa nie wykonują podwójnych obliczeń finansowych . Wykonuj obliczenia finansowe w systemie dziesiętnym ; do tego służy. Używaj podwójnego do rozwiązywania problemów fizycznych , a nie finansowych .
Główną wadą projektową twojego programu jest to, że polityka jest w niewłaściwym miejscu . Kto jest odpowiedzialny za obliczanie podatków? To produkt jest odpowiedzialny za obliczanie podatków, ale kiedy kupujesz jabłko, książkę lub pralkę, rzecz, którą zamierzasz kupić, nie jest odpowiedzialna za określenie, ile podatku zamierzasz zapłacić to. Za poinformowanie Cię o tym odpowiada polityka rządu . Twój projekt w znacznym stopniu narusza podstawową zasadę projektowania obiektów obiektowych, zgodnie z którą obiekty powinny być odpowiedzialne za własne sprawy , a nie za nic innego. Problemem pralki jest pranie ubrań, a nie pobieranie odpowiedniego cła przywozowego. Jeśli zmieniają się przepisy podatkowe, nie chcesz się zmieniaćpralka , chcesz zmienić obiekt zasad .
Jak więc podejść do tego rodzaju problemów w przyszłości?
Zacząłbym od podkreślenia wszystkich ważnych rzeczowników w opisie problemu:
Jakie są relacje między tymi wszystkimi rzeczownikami?
... i tak dalej. Po opracowaniu wszystkich relacji między wszystkimi rzeczownikami możesz rozpocząć projektowanie hierarchii klas. Istnieje abstrakcyjna klasa bazowa Item. Książka dziedziczy po nim. Istnieje abstrakcyjna klasa SalesTax; BasicSalesTax dziedziczy po nim. I tak dalej.
źródło
double
jest idealny w sytuacjach, w których znajdowanie się w granicach 0,00000001% prawidłowej odpowiedzi jest więcej niż wystarczające. Jeśli chcesz dowiedzieć się, jak szybko spada cegła po pół sekundy, wykonaj obliczenia w grze podwójnej. Kiedy wykonujesz arithemę finansową w grach podwójnych, otrzymujesz odpowiedzi, takie jak cena po opodatkowaniu wynosi 43,79999999999999 dolarów, a to po prostu wygląda głupio, mimo że jest bardzo bliskie poprawnej odpowiedzi.Jeśli firma powie coś o bibliotekach takich jak NUnit, JUnit lub Test :: Unit, jest więcej niż prawdopodobne, że TDD jest dla nich naprawdę ważne. W twoim przykładzie kodu nie ma żadnych testów.
Postaram się wykazać praktyczną znajomość:
Chciałbym zarekomendować stronę www.dimecasts.net jako imponujące źródło bezpłatnych, dobrej jakości screencastów, które obejmują wszystkie wyżej wymienione tematy.
źródło
Jest to wysoce subiektywne, ale oto kilka uwag, które chciałbym poruszyć na temat twojego kodu:
Moim zdaniem zmieszałeś
Product
iShoppingCartItem
.Product
Powinien zawierać nazwę produktu, status podatkowy itp., ale nie ilość. Ilość nie jest właściwością produktu - będzie inna dla każdego klienta firmy, która kupi dany produkt.ShoppingCartItem
powinien mieć aProduct
i ilość. W ten sposób klient może swobodnie kupić mniej więcej ten sam produkt. Przy obecnej konfiguracji nie jest to możliwe.Obliczanie ostatecznego podatku również nie powinno być częścią
Product
- powinno być częścią czegoś podobnego,ShoppingCart
ponieważ ostateczne obliczenie podatku może obejmować znajomość wszystkich produktów w koszyku.źródło
Przede wszystkim jest to bardzo dobre pytanie do wywiadu. To dobry miernik wielu umiejętności.
Jest wiele rzeczy, które musisz zrozumieć, aby udzielić dobrej odpowiedzi (nie ma idealnej odpowiedzi), zarówno na wysokim, jak i niskim poziomie. Oto kilka:
Stamtąd możesz przeprowadzić wiele interesujących dyskusji, obejmujących zasady projektowania (takie jak zasady SOLID), wzorce projektowe, wzorce analizy, modelowanie domeny, wybory technologiczne, ścieżki przyszłej ewolucji (np. Co jeśli dodam bazę danych lub bogatą warstwę interfejsu użytkownika, co należy zmienić?), kompromisy, wymagania niefunkcjonalne (wydajność, łatwość konserwacji, bezpieczeństwo, ...), testy akceptacyjne itp.
Nie będę komentował, jak powinieneś zmienić swoje rozwiązanie, po prostu powinieneś bardziej skupić się na tych koncepcjach.
Ale mogę pokazać, jak (częściowo) rozwiązałem ten problem , na przykładzie (w Javie). Zajrzyj do
Program
klasy, aby zobaczyć, jak to wszystko składa się na wydruk tego potwierdzenia:Zdecydowanie powinieneś rzucić okiem na te książki :-)
Tylko jako zastrzeżenie: moje rozwiązanie jest nadal bardzo niekompletne, po prostu skupiłem się na scenariuszu szczęśliwej ścieżki, aby mieć dobre podstawy do budowania.
źródło
Order
drukuje paragon, aleReceipt
wie o własnym formatowaniu. Ponadto TaxMethodPractice jest rodzajem polityki podatkowej, zawiera wszystkie podatki, które mają zastosowanie w określonym scenariuszu. TaxMethods to kalkulatory podatkowe. Czuję, że brakuje ci tylko jakiejś klasy wiązania wyższego poziomu , takiej jak proponowany SalesEngine. To ciekawy pomysł.Oprócz tego, że używasz klasy o nazwie product, nie wykazałeś, że wiesz, czym jest dziedziczenie, nie utworzyłeś dziedziczenia wielokrotnego z klasy Product, żadnego polimorfizmu. Problem mógł zostać rozwiązany przy użyciu wielu koncepcji OOP (nawet po to, aby pokazać, że je znasz). To jest problem z rozmową kwalifikacyjną, więc chcesz pokazać, ile wiesz.
Nie zamieniłbym się jednak teraz w depresję. To, że ich tutaj nie zademonstrowałeś, nie oznacza, że już ich nie znasz lub nie jesteś w stanie się ich nauczyć.
Potrzebujesz tylko trochę więcej doświadczenia z OOP lub wywiadami.
Powodzenia!
źródło
Osoby, które zaczęły uczyć się programowania z OOP, nie mają wielkich problemów ze zrozumieniem, co to znaczy, ponieważ jest tak jak w prawdziwym życiu . Jeśli masz umiejętności w zakresie programowania z innej rodziny niż OO, może to być trudniejsze do zrozumienia.
Przede wszystkim wyłącz ekran lub wyjdź z ulubionego środowiska IDE. Weź papier i ołówek i zrób listę bytów , relacji , ludzi , maszyn , procesów , rzeczy itp. Wszystko , co można napotkać w twoim ostatecznym programie.
Po drugie, spróbuj zdobyć różne podstawowe jednostki. Zrozumiesz, że niektórzy mogą mieć wspólne właściwości lub zdolności , musisz umieścić to w abstrakcyjnych obiektach . Powinieneś zacząć rysować ładny schemat swojego programu.
Następnie musisz podać funkcje (metody, funkcje, podprogramy, nazwij je tak, jak chcesz): na przykład obiekt produktu nie powinien mieć możliwości obliczenia podatku od sprzedaży . Obiekt silnika sprzedaży powinien.
Nie kłopocz się wszystkimi wielkimi słowami ( interfejsami , właściwościami , polimorfizmem , dziedzictwem itp.) I wzorcami projektowymi za pierwszym razem, nawet nie próbuj tworzyć pięknego kodu lub czegokolwiek ... Po prostu pomyśl o prostych obiektach i interakcje między nim jak w prawdziwym życiu .
Potem spróbuj przeczytać jakąś poważną, zwięzłą literaturę na ten temat. Myślę, że Wikipedia i Wikibooks to naprawdę dobry sposób na rozpoczęcie, a potem po prostu przeczytanie rzeczy o GoF i wzorcach projektowych oraz UML .
źródło
Najpierw nie mieszaj
Product
klasy z klasą Receipt (ShoppingCart
),quantity
powinna być częściąReceipItem
(ShoppingCartItem
), a takżeTax
&Cost
.TotalTax
ITotalCost
powinny być częściąShoppingCart
.Moja
Product
klasa ma tylkoName
&Price
& kilka właściwości tylko do odczytu, takich jakIsImported
:Twoja część obliczania podatku jest połączona z
Product
. Produkt nie definiuje zasad podatkowych, jest to klasy podatkowe. Opierając się na opisie problemu, istnieją dwa rodzaje podatków od sprzedaży:Basic
iDuty
podatki. Możesz użyć,Template Method Design Pattern
aby to osiągnąć:I wreszcie klasa do naliczania podatków:
Możesz je wypróbować na MyFiddle .
źródło
Bardzo dobrym punktem wyjścia do zasad projektowania są zasady SOLID .
Na przykład zasada Open Closed mówi, że jeśli chcesz dodać nową funkcjonalność, nie musisz dodawać kodu do istniejącej klasy, ale raczej dodać nową klasę.
W przypadku przykładowej aplikacji oznaczałoby to, że dodanie nowego podatku od sprzedaży wymagałoby dodania nowej klasy. To samo dotyczy różnych produktów, które są wyjątkami od reguły.
Zasada zaokrąglania oczywiście dotyczy oddzielnych klas - zasada pojedynczej odpowiedzialności mówi, że każda klasa ma jedną odpowiedzialność.
Myślę, że próba samodzielnego napisania kodu przyniosłaby znacznie więcej korzyści niż zwykłe napisanie dobrego rozwiązania i wklejenie go tutaj.
Prosty algorytm do napisania idealnie zaprojektowanego programu to:
źródło
Doskonała implementacja OOP jest całkowicie dyskusyjna. Z tego, co widzę w Twoim pytaniu, możesz modularyzować kod w oparciu o rolę, jaką pełnią w obliczaniu ostatecznej ceny, takiej jak produkt, podatek, baza danych produktu i tak dalej.
Product
może być klasą abstrakcyjną, a typy pochodne, takie jak Books, Food, mogą być z niej dziedziczone. O zastosowaniu podatku można decydować na podstawie typów pochodnych. Produkt wskazywałby, czy podatek ma zastosowanie, czy nie na podstawie klasy pochodnej.TaxCriteria
może być wyliczeniem, które można określić podczas zakupu (import, zastosowanie podatku od sprzedaży).Tax
class obliczy podatek na podstawieTaxCriteria
.Posiadanie,
ShoppingCartItem
zgodnie z sugestią XXBBCC, może zawierać przypadki produktu i podatku i jest to świetny sposób na segregację szczegółów produktu z ilością, całkowitą ceną z podatkiem itp.Powodzenia.
źródło
Z punktu widzenia ściśle OOA / D, jednym z głównych problemów, które widzę, jest to, że większość atrybutów klas ma nadmiarową nazwę klasy w nazwie atrybutu. np. cena produktu , typ produktu . W takim przypadku wszędzie tam, gdzie używasz tej klasy, będziesz mieć zbyt rozwlekły i nieco mylący kod, np. Product.productName. Usuń zbędne przedrostki / sufiksy nazw klas z atrybutów.
Nie widziałem też żadnych zajęć związanych z zakupem i tworzeniem paragonu, o który pytano w pytaniu.
źródło
Oto świetny przykład wzorca OO dla produktów, podatków, itp ... Zwróć uwagę na użycie interfejsów, które jest niezbędne w projektowaniu OO.
http://www.dreamincode.net/forums/topic/185426-design-patterns-strategy/
źródło
Zaatakowano problem kosztów z podatkiem przy użyciu wzorca gości.
źródło