Difference between revisions of "Visitor (padrão de desenho)/Exercício 1: Cálculo de Impostos"

From Wiki**3

< Visitor (padrão de desenho)
Line 352: Line 352:
 
   Person taxes (care): 1.0
 
   Person taxes (care): 1.0
  
[[category:OOP]]
+
[[category:Ensino]]
[[category:Teaching]]
+
[[category:PO]]
 
[[category:PO Exemplos]]
 
[[category:PO Exemplos]]
 +
[[category:Java]]

Revision as of 17:16, 23 October 2013

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

Class Taxpayer

<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>

Class Person

<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>

Class Company

<java5> import java.util.ArrayList;

/**

* A company has employees (persons).
* 
* We omitted the initialisation code.
*/

public class Company extends Taxpayer { /** * The employees in this company. */ private ArrayList<Person> _employees = new ArrayList<Person>();

/** * Simple constructor for initialising the company with some employees. */ public Company() { int count = (int) (Math.random() * 100); for (int i = 0; i < count; i++) _employees.add(new Person()); }

/** * @return size of company (number of employees). */ public int size() { return _employees.size(); }

/** * @param index * @return an employee */ public Person getEmployee(int index) { return _employees.get(index); }

/** * @see Taxpayer#accept(FriendlyIRS) */ @Override public double accept(FriendlyIRS irs) { return irs.taxCompany(this); } } </java5>

Class Region

<java5> import java.util.ArrayList;

/**

* A region has companies.
* 
* We omitted the initialisation code.
*/

public class Region extends Taxpayer { /** * The companies in this region. */ private ArrayList<Company> _companies = new ArrayList<Company>();

/** * Simple constructor for initialising the region with some companies. */ public Region() { int count = (int) (Math.random() * 100); for (int i = 0; i < count; i++) _companies.add(new Company()); }

/** * @return size of region (number of companies). */ public int size() { return _companies.size(); }

/** * @param index * @return a company */ public Company getCompany(int index) { return _companies.get(index); }

/** * @see Taxpayer#accept(FriendlyIRS) */ @Override public double accept(FriendlyIRS irs) { return irs.taxRegion(this); } } </java5>

Tax Computation (Visitors)

Class FriendlyIRS

The abstract class representing the concept of tax computation.

<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>

Class VanillaTaxes

Simple tax computation.

<java5> /**

* Usual tax calculator.
*/

public class VanillaTaxes extends FriendlyIRS {

/** * @see FriendlyIRS#taxCompany(Company) */ @Override public double taxCompany(Company company) { double tax = 0; for (int index = 0; index < company.size(); index++) tax += company.getEmployee(index).accept(this); return tax; }

/** * @see FriendlyIRS#taxPerson(Person) */ @Override public double taxPerson(Person person) { return 1; }

/** * @see FriendlyIRS#taxRegion(Region) */ @Override public double taxRegion(Region region) { double tax = 0; for (int index = 0; index < region.size(); index++) tax += region.getCompany(index).accept(this); return tax; }

} </java5>

Class BecauseWeCare

Discounted taxes.

<java5> /**

* The discount tax system.
*/

public class BecauseWeCare extends FriendlyIRS {

/** * Low water marker for revenue. */ private final int LOW = 1;

/** * Low water marker for population. */ private final int POP = 50;

/** * @see FriendlyIRS#taxCompany(Company) */ @Override public double taxCompany(Company company) { double tax = 0; for (int index = 0; index < company.size(); index++) tax += company.getEmployee(index).accept(this); if (company.size() < POP || tax < LOW) tax *= .9; return tax; }

/** * In this case, we chose not to test the LOW level (simply because we know * the value is the same). * * @see FriendlyIRS#taxPerson(Person) */ @Override public double taxPerson(Person person) { return 1; }

/** * @see FriendlyIRS#taxRegion(Region) */ @Override public double taxRegion(Region region) { double tax = 0; for (int index = 0; index < region.size(); index++) tax += region.getCompany(index).accept(this); if (region.size() < POP || tax < LOW) tax *= .9; return tax; }

} </java5>

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