Visitor (padrão de desenho)/Exercício 1: Cálculo de Impostos
From Wiki**3
Problem
Uma agência de cobrança de impostos tornou-se famosa por permitir adaptar métodos de cobrança de impostos de forma muito flexível. Os contribuintes (Taxpayer) são pessoas (Person), empresas (Company) e regiões (Region). As pessoas trabalham nas empresas e as empresas estão sediadas em regiões. Todos têm rendimentos (as pessoas e as regiões a partir das empresas e as empresas a partir de pessoas, regiões e outras empresas) e todos devem pagar os seus impostos.
O sucesso da agência advém da facilidade com que cria variações do seu produto, o premiado FriendlyIRS. Estas aplicações permitem interrogar cada contribuinte de forma adaptada, tanto ao contribuinte, como à situação de cobrança desejada.
Assim, além da cobrança em habitual, através do seu produto VanillaTaxes, permite ainda cobrar menos impostos se o rendimento for menor que um dado valor ou se a população (número de contribuintes numa empresa ou numa região) for inferior a um dado valor de referência. Para isso, disponibiliza o seu produto BecauseWeCare.
- A versão implementada por VanillaTaxes funciona por cobrança acumulada. Cada pessoa paga uma unidade monetária e cada empresa paga o equivalente à soma das contribuições individuais dos seus empregados. Cada região paga o equivalente à soma das contribuições das empresas nela sediadas.
- A versão implementada por BecauseWeCare é como a anterior, mas considera ainda se o rendimento apurado é inferior a limiares de referência (BecauseWeCare.LOW, para o rendimento mínimo, mas apenas para pessoas e empresas; e BecauseWeCare.POP, para a população mínima, apenas para regiões), aplicando desconto de 10% se se verificar algum limiar.
Implemente todas as classes mencionadas:
- Implemente esquematicamente as classes Taxpayer, Person, Company e Region, i.e., considere apenas as características estritamente necessárias para resolução do problema. As relações estruturais entre as classes devem ser explicitadas (atributos), mas não é necessário explicitar relações funcionais (métodos, interacção, etc.).
- Implemente completamente as classes FriendlyIRS, VanillaTaxes e BecauseWeCare.
Crie um exemplo (main) que ilustre a aplicação das diferentes classes.
Solution
Taxpayer Classes
| 'Ficheiro Taxpayer.java' |
|---|
|
<java5> /** * Basic taxpayer. */ public abstract class Taxpayer { /** * No actual value is returned in this case. * * @param irs * the visitor used to compute the revenue. * @return tax payed by this taxpayer. */ public double accept(FriendlyIRS irs) { throw new UnsupportedOperationException(); } } </java5> |
| 'Ficheiro Person.java' |
|---|
|
<java5> /** * Individual taxpayer. * * We omitted the initialisation code. */ public class Person extends Taxpayer { /** * @see Taxpayer#accept(FriendlyIRS) */ @Override public double accept(FriendlyIRS irs) { return irs.taxPerson(this); } } </java5> |
| 'Ficheiro Company.java' |
|---|
| {{{2}}} |
| 'Ficheiro Region.java' |
|---|
| {{{2}}} |
Tax Computation (Visitors)
The abstract class representing the concept of tax computation.
| 'Ficheiro FriendlyIRS.java' |
|---|
|
<java5> /** * The IRS computing visitor interface. */ public abstract class FriendlyIRS { /** * @param person * @return tax payed by this person. */ public abstract double taxPerson(Person person); /** * @param company * @return tax payed by this company. */ public abstract double taxCompany(Company company); /** * @param region * @return tax payed by this region. */ public abstract double taxRegion(Region region); } </java5> |
Simple tax computation.
| 'Ficheiro VanillaTaxes.java' |
|---|
| {{{2}}} |
Discounted taxes.
| 'Ficheiro BecauseWeCare.java' |
|---|
Example Application
<java5> /**
* Simple demo application. */
public class App {
/** * @param args */ public static void main(String[] args) { Taxpayer c1 = new Company(); Taxpayer r1 = new Region(); Taxpayer p1 = new Person();
FriendlyIRS vt = new VanillaTaxes(); FriendlyIRS ct = new BecauseWeCare();
System.out.println("Company taxes (vanilla): " + c1.accept(vt)); System.out.println("Region taxes (vanilla): " + r1.accept(vt)); System.out.println("Person taxes (vanilla): " + p1.accept(vt));
System.out.println("Company taxes (care): " + c1.accept(ct)); System.out.println("Region taxes (care): " + r1.accept(ct)); System.out.println("Person taxes (care): " + p1.accept(ct)); }
} </java5>
Compiling and Running
Compiling
Running
java App
Sample outputs:
Company taxes (vanilla): 21.0 Region taxes (vanilla): 4631.0 Person taxes (vanilla): 1.0 Company taxes (care): 18.900000000000002 Region taxes (care): 4505.800000000001 Person taxes (care): 1.0
Region has some companies with less than the minimum number of employees:
Company taxes (vanilla): 81.0 Region taxes (vanilla): 192.0 Person taxes (vanilla): 1.0 Company taxes (care): 81.0 Region taxes (care): 172.8 Person taxes (care): 1.0