¿Qué patrón de diseño puedo usar para crear objetos según el país/estado/ubicación para una aplicación de carrito de compras?

I am working on an application that will help me improve my OO design skills. I have almost completed the assignment but feel that I need to make my application more extensible and need some inputs on how to achieve this.

The problem domain can be described in a nutshell as follows:

The problem domain is to design a shopping cart application. There are different categories for an item such as food, books, etc. The rate of tax for which an item is eligible depends upon the category of the item. There are well defined tax policies, e.g basic tax of 10 % is applicable for all items except items belonging to the category food, all imported items are subject to additional import duty tax of 5 %.

The area I want to focus on is the module responsible for deciding the eligibility of an item for a given tax policy. I have used ideas from other people and the internet to come up with the following design for the tax module :

Design for shopping cart tax module

TaxCriteria : defines the condition that must be satisfied for an item to eligible for a TaxPolicy. Concrete implementers implement the isEligible method and provide the business logic for determining whether an item is eligible for a policy or not eg. isEligible method in ImportedTaxCriteria will check if an item is imported or not.

TaxPolicy : has a TaxCriteria, the rate at which the tax is applicable, and the name for the tax policy. The relation between TaxPolicy and TaxCriteria is based on the specification pattern.

SalesPolicy : is made up of one or more TaxPolicy instances.

SalesEngine : SalesEngine has a SalesPolicy and a TaxCalculator. The applyPolicies method is passed an Order that contains a list of items. applyPolicies will iterate through each item in the order and check its eligibility against each TaxPolicy in the sales policy and calculate the tax using a TaxCalculator based on the applicable policies.

The new problem domain :

Every country has different sales policies defined. Import duty in the US could be 5 percent whereas import duty in China could be 3 %. To address this requirement, I was thinking of using a simple factory pattern. SalesPolicy will no longer be a class but an interface with a getTaxPolicies method that returns a list of TaxPolicy. USASalesPolicy and ChinaSalesPolicy will implement SalesPolicy and the getTaxPolicies method will return a list of TaxPolicy pertaining to the specific country respectively. Similarly, every country will have its own tax calculation adjustments. USATaxCalculator and ChinaTaxCalculator can take care of indepent implementations.

Finally, SalesEngine will be passed a SalesPolicyFactory and a TaxCalculatorFactory in the constructor instead of directly passing a SalesPolicy and a TaxCalcualtor. The applyPolicies method will be passed an additional parameter which will be a String representing the country. The applyPolciies method will pass the country to the factories in SalesEngine and use them to create appropriate SalesPolicy and TaxCalculator instances to be used for calculating the tax.

This is what my thought process has been so far. Am I doing justice to the well defined design principles an the factory pattern? How can I use abstract factory pattern such that SalesPolicy and TaxCalculator represent the families of related products? Is there a better way to solve the problem than the one I have used?

preguntado el 28 de agosto de 12 a las 15:08

Am I right that it assumes that the tax criteria are the same in every country? Will, for instance, an article be tax exempt in all countries? -

I don't think that would be a good idea. Ideally, getTaxPolicies in USASalesPolicy should return list of TaxPolicy in which one of the TaxPolicy instances will be passed an ExemptedTaxCriteria that was created using the exempt method and passed in items to exempt specifically for USA. See the class skeleton for ExemptedTaxCriteria and the exempt method for clarification. ExemptedTaxCriteria has a private constructor so you use the exempt method and pass it the items to exempt instead. -

@Justin I would like to point out that this is not some kind of homework assignment. It's a real world application and a real world design problem. I have removed your edit on the tags. -

@bot Bad assumption on my part. The nature of the problem and your phrasing ("I am currently working on an assignment") led me to believe this had been assigned to you as homework. -

No worries. I have edited my post to avoid any ambiguity! -

2 Respuestas

You can, if you wish, incorporate the Abstract Factory pattern to deal with the creation of TaxPolicy objects.

In your case that would involve:

AbstractTaxPolicyFactory – an interface with abstract methods createItemCategoryTaxPolicy() y createImportDutyTaxPolicy(), that would create abstract tax policies ItemCategoryTaxPolicy y ImportDutyTaxPolicy (these would be your "families of related products")

USTaxPolicyFactory y ChinaTaxPolicyFactory – two concrete factories, each implementing those two methods to create concrete tax policies like ChinaImportDutyTaxPolicy, etc.

ItemCategoryTaxPolicy y ImportDutyTaxPolicy – interfaces for the respective concrete tax policies

USItemCategoryTaxPolicy, USImportDutyTaxPolicy, ChinaItemCategoryTaxPolicy y ChinaImportDutyTaxPolicy – the four concrete tax policies. For instance, at runtime the USImportDutyTaxPolicy would be created by the USTaxPolicyFactory, and would be of ImportDutyTaxPolicy tipo.

SalesPolicy would be your client that would use the abstract factory and abstract tax policies interfaces, e.g.:

AbstractTaxPolicyFactory absFactory = new ChinaTaxPolicyFactory();
// or use a static factory method: 
// TaxPolicyFactoryCreator.createNewFactory(Country.CHINA); 
ItemCategoryTaxPolicy itemCatTaxPolicy = absFactory.createItemCategoryTaxPolicy();
ImportDutyTaxPolicy importDutyTaxPolicy = absFactory.createImportDutyTaxPolicy();

Respondido 28 ago 12, 21:08

I'd use the Factory pattern. Implement/design a factory class that will accept locale information and which will return a class that implements the behaviors you describe above. The implementation of those behaviors will change from country to country and city to city, so the factory has to figure out and return which specific class provides the correct implementation for the locale.

Respondido 28 ago 12, 15:08

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.