Problema
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.
Solução
Taxpayer Classes
[Expand] Ficheiro Taxpayer.java
|
/**
* 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();
}
}
|
[Expand] Ficheiro Person.java
|
/**
* 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);
}
}
|
[Expand] Ficheiro Company.java
|
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);
}
}
|
[Expand] Ficheiro Region.java
|
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);
}
}
|
Tax Computation (Visitors)
The abstract class representing the concept of tax computation.
[Expand] Ficheiro FriendlyIRS.java
|
/**
* 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);
}
|
Simple tax computation.
[Expand] Ficheiro VanillaTaxes.java
|
/**
* 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;
}
}
|
Discounted taxes.
[Expand] Ficheiro BecauseWeCare.java
|
/**
* 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;
}
}
|
Example Application
Simple demo application.
[Expand] Ficheiro App.java
|
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));
}
}
|
Compiling and Running
Compiling
javac App.java
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