Recientemente estuve intentando para una empresa 'x'. Me enviaron una serie de preguntas y me dijeron que resolviera solo una.
El problema es así:
El impuesto básico sobre las ventas se aplica a una tasa del 10% sobre todos los bienes, excepto libros, alimentos y productos médicos que están exentos.
Los derechos de importación son un impuesto sobre las ventas adicional que se aplica a todos los productos importados a una tasa del 5%, sin exenciones.
Cuando compro artículos, recibo un recibo que enumera el nombre de todos los artículos y su precio (impuestos incluidos), terminando con el costo total de los artículos y las cantidades totales de impuestos sobre las ventas pagados.
Las reglas de redondeo para el impuesto a las ventas son que para una tasa impositiva de n%, un precio de venta libre de p contiene (np / 100 redondeado al 0.05 más cercano) la cantidad de impuesto a las ventas.
"Me dijeron que están interesados en el aspecto de diseño de su solución y les gustaría evaluar mis habilidades de programación orientada a objetos ".
Esto es lo que dijeron con sus propias palabras
- Para la solución, queremos que use Java, Ruby o C #.
- Estamos interesados en el ASPECTO DE DISEÑO de su solución y nos gustaría evaluar sus habilidades de programación orientada a objetos .
- Puede utilizar bibliotecas o herramientas externas con fines de creación o prueba. Específicamente, puede usar bibliotecas de pruebas unitarias o herramientas de compilación disponibles para su idioma elegido (por ejemplo, JUnit, Ant, NUnit, NAnt, Test :: Unit, Rake, etc.)
- Opcionalmente, también puede incluir una breve explicación de su diseño y suposiciones junto con su código.
- Tenga en cuenta que NO esperamos una aplicación basada en web o una interfaz de usuario completa. Más bien, estamos esperando una aplicación simple basada en consola e interesada en su código fuente.
Así que proporcioné el siguiente código: puede copiar, pegar el código y ejecutarlo en 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
}
}
puede descomprimir la entrada y ejecutarla para diferentes entradas.
Di la solución, pero me rechazaron.
"Dijeron que no pueden considerarme para nuestras posiciones abiertas actuales porque la solución del código no es satisfactoria".
Por favor, guíame lo que falta aquí. ¿Esta solución no es una buena solución OOAD?
¿Cómo puedo mejorar mis habilidades OOAD?
Mis personas mayores también dicen que la aplicación OOAD perfecta tampoco funcionará de manera práctica.
Gracias
Respuestas:
En primer lugar, Dios mío, no haga cálculos financieros al doble . Haga cálculos financieros en decimal ; Esto es para lo que sirve. Utilice el doble para resolver problemas de física , no problemas financieros .
El principal defecto de diseño de su programa es que la política está en el lugar equivocado . ¿Quién se encarga de calcular los impuestos? Has puesto el producto a cargo de calcular los impuestos, pero cuando compras una manzana o un libro o una lavadora, lo que estás a punto de comprar no es responsable de decirte cuánto impuesto vas a pagar. eso. La política del gobierno es responsable de decirle eso. Su diseño viola masivamente el principio básico de diseño de OO de que los objetos deben ser responsables de sus propias preocupaciones y no de las de nadie más. La preocupación de una lavadora es lavar la ropa, no cobrar los derechos de importación adecuados. Si cambian las leyes fiscales, no quiere cambiarel objeto de la lavadora , desea cambiar el objeto de política .
Entonces, ¿cómo abordar este tipo de problemas en el futuro?
Habría comenzado resaltando cada sustantivo importante en la descripción del problema:
Ahora bien, ¿cuáles son las relaciones entre todos esos sustantivos?
... y así. Una vez que haya resuelto todas las relaciones entre todos los sustantivos, puede comenzar a diseñar una jerarquía de clases. Hay un elemento de clase base abstracto. Libro hereda de él. Hay una clase abstracta SalesTax; BasicSalesTax hereda de él. Y así.
fuente
double
es ideal para situaciones en las que estar dentro del 0.00000001% de la respuesta correcta es más que suficiente. Si quieres saber qué tan rápido cae un ladrillo después de medio segundo, haz los cálculos en dobles. Cuando haces aritemética financiera en dobles, terminas con respuestas como el precio después de impuestos es 43.79999999999999 dólares y eso parece una tontería a pesar de que está muy cerca de la respuesta correcta.Si la empresa dice algo sobre bibliotecas como NUnit, JUnit o Test :: Unit, es más que probable que TDD sea realmente importante para ellos. En su ejemplo de código no hay pruebas en absoluto.
Intentaría demostrar un conocimiento práctico de:
Me gustaría recomendar www.dimecasts.net como una fuente impresionante de screencasts gratuitos y de buena calidad que cubren todos los temas mencionados anteriormente.
fuente
Esto es muy subjetivo, pero aquí hay algunos puntos que haría sobre su código:
En mi opinión, mezcló
Product
yShoppingCartItem
.Product
debe tener el nombre del producto, el estado fiscal, etc. pero no la cantidad. La cantidad no es una propiedad de un producto, será diferente para cada cliente de la empresa que compre ese producto en particular.ShoppingCartItem
debe tener unaProduct
y la cantidad. De esa forma, el cliente puede comprar libremente más o menos del mismo producto. Con su configuración actual eso no es posible.El cálculo del impuesto final tampoco debería ser parte del
Product
- debería ser parte de algo así,ShoppingCart
ya que el cálculo final del impuesto puede implicar conocer todos los productos en el carrito.fuente
Primero que nada, esta es una muy buena pregunta de entrevista. Es un buen indicador de muchas habilidades.
Hay muchas cosas que debe comprender para proporcionar una buena respuesta (no existe una respuesta perfecta), tanto de alto nivel como de bajo nivel. Aquí hay un par:
A partir de ahí, puede tener muchas discusiones interesantes, que involucran principios de diseño (como los principios SOLID), patrones de diseño, patrones de análisis, modelado de dominio, opciones de tecnología, rutas de evolución futuras (por ejemplo, ¿qué pasa si agrego una base de datos o una capa de interfaz de usuario rica, ¿Qué necesita cambiar?), compensaciones, requisitos no funcionales (rendimiento, mantenibilidad, seguridad, ...), pruebas de aceptación, etc.
No comentaré cómo debería cambiar su solución, solo que debería centrarse más en estos conceptos.
Pero, puedo mostrarles cómo resolví (parcialmente) este problema , solo como un ejemplo (en Java). Mire en la
Program
clase para ver cómo se junta todo para imprimir este recibo:Definitivamente deberías echar un vistazo a esos libros :-)
Solo como advertencia: mi solución aún está muy incompleta, solo me concentré en el escenario del camino feliz para tener una buena base sobre la cual construir.
fuente
Order
imprime el recibo, peroReceipt
conoce su propio formato. Además, TaxMethodPractice es una especie de política fiscal, contiene todos los impuestos que se aplican a un determinado escenario. TaxMethods son calculadoras de impuestos. Siento que solo le falta una clase de enlace de nivel superior , como su SalesEngine propuesto. Es una idea interesante.Excepto por el hecho de que está utilizando una clase llamada producto, no ha demostrado que sepa qué es la herencia, no ha creado herencias múltiples clasificadas de Producto, sin polimorfismo. El problema podría haberse resuelto utilizando múltiples conceptos de programación orientada a objetos (incluso solo para demostrar que los conoce). Este es un problema de la entrevista, por lo que querrá demostrar cuánto sabe.
Sin embargo, no me convertiría en depresión en este momento. El hecho de que no los haya demostrado aquí no significa que no los conozca o que no pueda aprenderlos.
Solo necesita un poco más de experiencia con OOP o entrevistas.
¡Buena suerte!
fuente
Las personas que han comenzado a aprender a programar con POO no tienen grandes problemas para entender lo que significa, porque es como en la vida real . Si tiene habilidades con otras familias de programación además de OO, podría ser más difícil de entender.
En primer lugar, apague la pantalla o salga de su IDE favorito. Tome un papel y un lápiz y haga una lista de entidades , relaciones , personas , máquinas , procesos , cosas , etc., todo lo que pueda encontrar en su programa final.
En segundo lugar, intente obtener las diferentes entidades básicas . Comprenderás que algunos pueden compartir propiedades o habilidades , tienes que ponerlo en objetos abstractos . Debería empezar a dibujar un buen esquema de su programa.
A continuación, debe poner funciones (métodos, funciones, subrutinas, llámelo como desee): por ejemplo, un objeto de producto no debería poder calcular el impuesto sobre las ventas . Un objeto de motor de ventas debería.
No se sienta en problemas con todas las palabras importantes ( interfaces , propiedades , polimorfismo , herencia , etc.) y patrones de diseño por primera vez, ni siquiera intente crear un código hermoso o lo que sea ... Solo piense en objetos simples y interacciones entre ellos como en la vida real .
Después, intente leer literatura seria y concisa sobre esto. Creo que Wikipedia y Wikilibros son una muy buena manera de comenzar y luego leer cosas sobre GoF y Design Patterns y UML .
fuente
Primero, no mezcle la
Product
clase con la clase Receipt (ShoppingCart
),quantity
debe ser parte deReceipItem
(ShoppingCartItem
), así comoTax
&Cost
. ElTotalTax
&TotalCost
debe formar parte deShoppingCart
.Mi
Product
clase, solo tieneName
&Price
& algunas propiedades de solo lectura comoIsImported
:Su parte de cálculo de impuestos está emparejada con
Product
. Un producto no define políticas fiscales, son clases de impuestos. Según la descripción del problema, existen dos tipos de impuestos sobre las ventas:Basic
eDuty
impuestos. Puedes usarTemplate Method Design Pattern
para lograrlo:Y finalmente una clase para aplicar impuestos:
Puedes probarlos en MyFiddle .
fuente
Un muy buen punto de partida sobre las reglas de diseño son los principios SOLID .
Por ejemplo, el principio Abierto Cerrado establece que si desea agregar una nueva funcionalidad, no tiene que agregar código a la clase existente, sino que debe agregar una nueva clase.
Para su aplicación de muestra, esto significaría que agregar un nuevo impuesto sobre las ventas requeriría agregar una nueva clase. Lo mismo ocurre con los diferentes productos que son excepciones a la regla.
La regla de redondeo, obviamente, va en una clase separada: el principio de responsabilidad única establece que cada clase tiene una sola responsabilidad.
Creo que intentar escribir el código usted mismo traerá muchos más beneficios que simplemente escribir una buena solución y pegarla aquí.
Un algoritmo simple para escribir el programa diseñado perfecto sería:
fuente
Una implementación OOP perfecta es completamente discutible. Por lo que veo en su pregunta, podría modularizar el código en función de la función que desempeñan para calcular el precio final, como Producto, Impuesto, ProductDB, etc.
Product
podría ser una clase abstracta y los tipos derivados como Books, Food podrían heredarse de ella. La aplicabilidad fiscal puede decidirse por los tipos derivados. El producto indicaría si el impuesto es aplicable o no según la clase derivada.TaxCriteria
puede ser una enumeración y esto se puede especificar durante la compra (importado, aplicabilidad del impuesto sobre las ventas).Tax
la clase calculará el impuesto en base aTaxCriteria
.Tener un
ShoppingCartItem
tal como lo sugiere XXBBCC puede encapsular instancias de Producto e Impuestos y es una excelente manera de segregar los detalles del producto con cantidad, precio total con impuestos, etc.Buena suerte.
fuente
Desde una perspectiva estrictamente OOA / D, un problema importante que veo es que la mayoría de los atributos de su clase tienen el nombre redundante de la clase en el nombre del atributo. por ejemplo , precio del producto , tipo de producto . En este caso, dondequiera que use esta clase, tendrá un código demasiado detallado y algo confuso, por ejemplo, product.productName. Elimine los prefijos / sufijos de nombre de clase redundantes de sus atributos.
Además, no vi ninguna clase relacionada con la compra y la creación de un recibo como se preguntó en la pregunta.
fuente
Este es un gran ejemplo de un patrón OO para Productos, Impuestos, etc. Observe el uso de Interfaces, que es esencial en el diseño OO.
http://www.dreamincode.net/forums/topic/185426-design-patterns-strategy/
fuente
Atacó el problema del costo con impuestos usando un patrón de visitante.
fuente