Реалізація податкового движка і податкового рахунку додатки для обчислення податків Visual C # (Sharp)

Для реалізації канадського податкового движка потрібен клас, похідний від клаа BaseTaxEngine Це означає, що необхідно реалізувати метод CreateTaxAccount () Крім цього, потрібно створити відповідне простір імен, що називається, скажімо, LibTax Canada Подробиці простору імен не відображаються в коді, т к вони вказуються неявно Реалізація виглядатиме таким чином:

internal class TaxEngine : BaseTaxEngine {

public override ITaxAccount CreateTaxAccount() { return new TaxAccount()

}

}

У реалізації методу CreateTaxAccount () створюється екземпляр класу TaxAccount Це похідний клас від класу BaseTaxAccount і тому реалізує інтерфейс ITaxAccount Реалізація класу TaxAccount виглядає таким чином:

internal class TaxAccount : BaseTaxAccount { Province _province

int _year

public TaxAccount() {

}

public override double GetTaxRate(double income) { if (_year == 2007) {

if („province == ProvinceOntario) { return OntarioTax2007TaxRate(income)

}

}

throw new NotsupportedException(&quotYear &quot + _year + &quot Province &quot +

„province + &quot not supported&quot)

}

}

Метод GetTaxRate () повертає відповідну податкову ставку для даної суми оподатковуваного доходу Як уже згадувалося, в Канаді податкова ставка залежить від провінції, в якій проживає платник податків, і від року, за який

сплачується податок Метод GetTaxRate про реалізує можливість обчислення ногов за 2007 рік для провінції Онтаріо

Але тут у нас є проблема з членами даних _province і _уеаг Ці члени даних використовуються в обчисленнях у методі GetTaxRate про, але їм не присвоєно значення

Присвоєння стану, коли цього не може зробити інтерфейс

Проблема з канадським податковим рахунком є ​​поширеною і зустрічається в багатьох ситуаціях Суть її полягає в тому, що необхідно призначити стояння, специфічне для реалізації, не порушуючи при цьому первісне призначення загального інтерфейсу

Для ілюстрації проблеми скажемо, що метод GetTaxRate про буде містити посилання на провінцію і рік Відповідним чином модифікований іерфейс ITaxAccount буде виглядати так:

public interface ITaxAccount {

void AddDeduction(ITaxDeduction deduction) void Addlncome(ITaxIncome income)

double GetTaxRate(double income, Province province, int year)

ITaxDeduction[] Deductions { get } ITaxIncome[] Income { get }

}

Додаткові параметри для обчислення канадських податків виділені жирним шрифтом Але чи добре таке рішення Ні, це особливо погане рішення Даие параметри є специфічними для реалізації, в Зокрема, для Канака реалізації

Параметр year ще можна виправдати, т к у багатьох країнах податкова ставка і види оподатковуваного доходу залежать від конкретного року Але для параметра province немає ніяких підстав Уявіть собі, що вам потрібно реалізувати британську податкову систему, при цьому вказуючи графство (аналог провінції), тоді як у Великобританії місцеві податки не стягуються

Можливим рішенням цієї проблеми може бути перевизначення інтерфейсу наступним чином:

public class Specifics {

public Province CanadianProvince public State AmericanState

}

public interface ITaxAccount {

void AddDeduction(ITaxDeduction deduction) void Addlncome(ITaxIncome income)

double GetTaxRate{double income, int year, Specifics specifics) ITaxDeduction[] Deductions { get }

ITaxIncomeU Income { get }

}

У даній реалізації застосовується параметр specifics типу Specifics Тип specifics визначає клас, що містить різноманітну інформацію, необхідний для визначення правильної ставки податку Але підхід із застосуванням класу specifics неправильний з наступних причин:

• він повинен знати реалізацію, що у випадку з спадкуванням є поганою ідеєю Це подібно вимогу, щоб у ресторані обслуговуючий нас офіцнт був блондином

• навіть якщо застосування типу Specifics і було б прийнятним, то в завісімт від кількості реалізованих податкових систем нам довелося б додавати або прибирати з нього дані Це погана ідея, т к виникають складності в олужіваніем коду

Таким чином, розглянуті рішення не є прийнятними Крім цього, у нас все ще залишається проблема вирішення, яку податкову ставку використовувати

Реалізація ідей з типом Specifics

Щоб реалізувати рішення, почнемо з виправлення класу TaxAccount Модіфірованная версія класу буде містити певний тип функціональності з членами даних, які вказують рік і провінцію Виправлена ​​реалізація класу TaxAccount буде виглядати так:

internal class TaxAccount : BaseTaxAccount { Province „province

int „year

public TaxAccount(Province province, int year) {

„province = province year = year

}

public override double GetTaxRate(double income) { if („year == 2007) {

if („province == ProvinceOntario) { return OntarioTax2007TaxRate(income)

}

}

throw new NotSupportedException(&quotYear &quot + „year + &quot Province &quot +

„province + &quot not supported&quot)

}

}

Щоб виправити клас, ми додали конструктор, що містить як паретров провінцію і рік Це досить поширене рішення проблеми, при якому ми не змінюємо інтерфейси, а просто міняємо спосіб створення примірників реалізацій Памятайте, що коли ми створюємо екземпляр конкретної реалізації, то знаємо, яка функціональність нам потрібно, і тому можемо надати долнітельние параметри Коли ми знаходимося на рівні інтерфейсу, то повинні обійтися використанням тільки загальних ідей

Тепер нам потрібно виправити клас TaxEngine Він є відповідальним за соан примірника TaxAccount, тому, для того щоб створити екземпляр класу TaxAccount для канадської податкової системи, йому необхідні додаткові параметри:

internal class TaxEngine : BaseTaxEngine {

public override ITaxAccount CreateTaxAccount() { return new TaxAccount(ProvinceOntario, 2007)

}

}

У реалізації методу GreateTaxAccount () передбачається, що податки обчислюються за 2007 рік для провінції Онтаріо Дане рішення обходить стороною питання, яким чином обчислювати податки для платника податків, наприклад, з Британської Колумбії за 2008 рік

Подивившись на реалізацію класу TaxEngine, ми побачимо, що він досить Неболей обсягу Це наштовхує на думку, що можна створити тип TaxEngine для кдой провінції для кожного року Далі показані два приклади таких класів:

internal class Ontario2007TaxEngine : BaseTaxEngine { public override ITaxAccount CreateTaxAccount() {

return new TaxAccount(ProvinceOntario, 2007)

}

}

internal class BritishColumbia2008TaxEngine : BaseTaxEngine { public override ITaxAccount CreateTaxAccount() {

return new TaxAccount(ProvinceBritishColumbia, 2008)

}

}

Це рішення не таке і погане, т к для того щоб створити екземпляр необхідний податкового движка, нам потрібно лише визначити фабрику, яка знає, еемпляр якого класу потрібно створити Але для даної проблеми таке рішення бет надзвичайно трудомістким, тому що воно може вилитися в сотні, якщо не тисячі, визначень класу TaxEngine Рішення такого типу, зі специфічними реалізуються, є прийнятним тільки у випадках з обмеженим числом варіантів, близько 10-12

Кращим підходом буде додати інтерфейс, специфічний для канадської податком системи Працює такий підхід таким чином При створенні екземпляра

податкового движка нам потрібно буде знати, яку податкову систему іспользать Фабрика рятує нас від необхідності знати, примірник якого з типів потрібно створити, але немає нічого поганого в наданні фабриці певної додаткової інформації

Таким чином, правильним рішенням буде створити новий інтерфейс, називається icanadaTaxEngine Даний інтерфейс додає методи фабрики для соан примірників типів з параметрами, специфічними для певної реалаціі Визначення інтерфейсу icanadaTaxEngine виглядає таким чином:

public enum Province { Alberta, BritishColumbia, Manitoba, NewBrunswick, Newfoundland Labrador, NovaScotia,

Nunavut,

Ontario, PrinceEdwardlsland, Quebec, Saskatchewan,  Yukon

}

public interface IcanadaTaxEngine {

ITaxAccount CreateTaxAccount(Province province, int year) ITaxIncome CreateCapitalGain(double amount)

}

Визначення icanadaTaxEngine містить два додаткові методи:

• метод CreateTaxAccount () створює екземпляр податкового рахунку для определеятся провінції та року

• метод CreateCapitalGain () створює екземпляр ITaxIncome, користуючись обчислень-

нями для канадських капітальних доходів Реалізація TaxEngine стає наступною:

internal class TaxEngine : BaseTaxEngine, IcanadaTaxEngine {

public override ITaxAccount CreateTaxAccount() { return new TaxAccount(ProvinceOntario, 2007)

}

public ITaxAccount CreateTaxAccount(Province province, int year) { return new TaxAccount(province, year)

}

public ITaxIncome CreateCapitalGain(double amount) { return new Taxlncame(amount, 050)

}

}

У модифікованій реалізації клас TaxEngine також є похідним від класу BaseTaxEngine, таким чином, задовольняючи вимогам, розпорядчим, щоб це був податковий движок загального призначення А для додаткових требаній канадської податкової системи ми реалізуємо інтерфейс icanadaTaxEngine

Визначення інтерфейсу для конкретної податкової системи є нормаллю, т к такий інтерфейс не привязаний до якої-небудь певної реалізації Щоб краще розуміти даний метод реалізації, конкретний інтерфейс можна розглядати як характеристику, яку може підтримувати реалізація Це випливає з прикладу з фігурами, коли квадрат може підтримувати як інтеейс I Square, так І інтерфейс IRectangle

Останнім кроком у створенні податкового движка буде його застосування Далі наводиться приклад обчислення податків за 2007 рік для провінції Онтаріо

ITaxEngine engine = EngineCreatorCreateCanadianTaxEngine() ICanadaTaxEngine canadaEngine = engine as ICanadaTaxEngine ITaxAccount account = canadaEngineCreateTaxAccount(ProvinceOntario, 2007)

ITaxIncome income = engineCreatelncome(100)

ITaxIncome capitalGain = canadaEngineCreateCapitalGain(100) accountAddlncome(income)

accountAddlncome(capitalGain)

ITaxDeduction deduction = engineCreateDeduction(20) accountAddDeduction(deduction)

double taxToPay = engineCalculateTaxToPay(account)

ConsoleWriteLine(&quotTax to pay (&quot + taxToPay + &quot)&quot)

Зверніть увагу на визначення змінних engine і canadaEngine Це ноально, т к ми вибираємо характеристику, яка може бути динамічно зрошена

Джерело: Гросс К С # 2008: Пер з англ – СПб: БХВ-Петербург, 2009 – 576 е: ил – (Самовчитель)

Схожі статті:


Сподобалася стаття? Ви можете залишити відгук або підписатися на RSS , щоб автоматично отримувати інформацію про нові статтях.

Коментарів поки що немає.

Ваш отзыв

Поділ на параграфи відбувається автоматично, адреса електронної пошти ніколи не буде опублікований, допустимий HTML: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

*

*