EXtreme Programming XP Тема 3. XP Пусть есть некоторая информационная система для банков. В качестве основной валюты для расчетов используется доллар,

Презентация:



Advertisements
Похожие презентации
Ассоциативные списки Поиск данных происходит не по индексу или положению объекта, а по его ассоциативной связи: public interface Map { // Доступ к объектам.
Advertisements

Учебный курс Объектно-ориентированный анализ и программирование Лекция 7 Методы как средство реализации операций Лекции читает кандидат технических наук.
Лекция 4. Введение в С++ Наследование, множественное наследование. Конструкторы, деструкторы. Виртуальные функции.
Лекция 2 Наследование Наследование в Java имеет тот же смысл, что и в С++. Однако наследование в Java осуществляется при помощи ключевого слова extends.
АССОЦИАТИВНЫЕ КОЛЛЕКЦИИ Лекция 6 1. Отличие от последовательных 2 В последовательной коллекции каждый элемент ассоциируется с номером, начиная с 0. В.
Лекция 8. Введение в ООП. Часть 1 Красс Александр СПбГУ ИТМО, 2008.
Наследование Наследование – это отношение является между классами. class Person { string first_name; int birth_year;... } class Student : Person { float.
Синтаксис языка Java. Символы и синтаксис Перевод строчки эквивалентен пробелу Регистр в именах различается.
Java. Part 2. Спецификаторы доступа public private protected не указан – доступ в пределах пакета Могут использоваться перед классами, методами, полями.
Перегрузка операторов x = a + b результат 1-й операнд2-й операнд оператор По количеству операндов операторы делятся на: унарные (один операнд) бинарные.
Наследование time time_with_sec В чем преимущества наследования? Наследование кода – поля, метод inc Появилось два класса с которыми точно можно обращаться.
Преобразования типов В языке C/C++ имеется несколько операций преобразования типов. Они используются в случае, если переменная одного типа должна рассматриваться.
Кафедра ОСУ, Java 2004 Слайд 1 Наследование Наследование позволяет использовать существующий класс для определения новых классов, т.е. способствует.
Д.з Язык С++ - занятие 31. Задача 1: 1/1 + 1/3 + 1/5 … #include using namespace std; int main() { int n; cin >> n; double sum = 0;// Сумма for.
Делегаты Как созданные объекты могут посылать сообщения тем объектам, которые их породили? При программировании под Windows на С и C++ основное средство.
Высокоуровневые методы информатики и программирования Лекция 10 События.
Основы ООП и C# Работа с объектами и классами. Классы Класс специальный тип данных для описания объектов. Он определяет данные и поведение типа. Определение.
Обобщения ( generics) Обобщения – это классы, структуры, интерфейсы и методы, в которых некоторые типы сами являются параметрами. Эти типы перечисляются.
Классы в С#. Перечисления С# Перечисление задает конечное множество возможных значений, которые могут получать объекты класса перечисление. [атрибуты][модификаторы]
Java, каф.ОСУ, АВТФ1 Наследование Наследование позволяет использовать существующий класс для определения новых классов, т.е. способствует многократному.
Транксрипт:

eXtreme Programming XP Тема 3

XP Пусть есть некоторая информационная система для банков. В качестве основной валюты для расчетов используется доллар, для работы с которым был реализован класс Dollar. В условиях кризиса требовалось перевести систему на мультивалютные расчеты.

XP $5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 public void testMultiplication() { Dollar five=new Dollar(5); five.times(2); assertEquals(10.,five.amount); } public class Dollar { double amount; Dollar (double amount) {} void times(int mult) {} }

XP При объявлении переменной amount: double amount=5*2; В методе times: void times(int mult){ amount=5*2;} Изменения должны быть и в конструкторе, и в методе times: Dollar (double amount){this.amount=amount;} void times(int mult) {amount*=mult;}

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин Тест, который не выполняется: public void testMultiplication() { Dollar five=new Dollar(5); five.times(2); assertEquals(10.,five.amount); five.times(3); assertEquals(15.,five.amount); } XP

Изменение метода times: Dollar times(int mult) { return new Dollar(amount*mult); } Изменение теста: public void testMultiplication() { Dollar five=new Dollar(5); Dollar product=five.times(2); assertEquals(10.,product.amount); product=five.times(3); assertEquals(15.,product.amount); } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Тест на равенство: public void testEquality() { assertTrue(new Dollar(5).equals(new Dollar(5))); } Тест не работает – нужна заглушка метода equals. public boolean equals(Object obj){return true;} XP

Не работает другой тест: public void testEquality() { assertTrue(new Dollar(5).equals(new Dollar(5))); assertFalse(new Dollar(5).equals(new Dollar(6))); } Требуется изменить метод equals: public boolean equals(Object obj) { Dollar dollar=(Dollar)obj; return amount==dollar.amount; } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов XP

Меняем тест – сравниваем на равенство объекты: public void testMultiplication() { Dollar five=new Dollar(5); assertEquals(new Dollar(10),five.times(2)); assertEquals(new Dollar(15),five.times(3)); } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF XP

Добавляем новый класс Franc (код из класса Dollar); Пишем тест: public void testFrancMultiplication() { Franc five=new Franc(5); assertEquals(new Franc(10),five.times(2)); assertEquals(new Franc(15),five.times(3)); } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() XP

Создадим класс Money, от которого наследуют Dollar и Franc Перенесем в него переменную amount. Для выполнения всех тестов требуется сделать ее protected. XP

Меняем в классе Dollar метод equals – перенос на тип данных Money public boolean equals(Object obj) { Money money=(Money)obj; return amount==money.amount; } Переносим метод в класс Money и удаляем из классов Dollar и Franc. Тест: public void testEquality() { assertTrue(new Dollar(5).equals(new Dollar(5))); assertFalse(new Dollar(5).equals(new Dollar(6))); assertTrue(new Franc(5).equals(new Franc(5))); assertFalse(new Franc(5).equals(new Franc(6))); } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() Сравнение долларов и франков XP

Тест: public void testEquality() { assertTrue(new Dollar(5).equals(new Dollar(5))); assertFalse(new Dollar(5).equals(new Dollar(6))); assertTrue(new Franc(5).equals(new Franc(5))); assertFalse(new Franc(5).equals(new Franc(6))); assertFalse(new Franc(5).equals(new Dollar(5))); } Изменение метода: public boolean equals(Object obj) { Money money=(Money)obj; return amount==money.amount && getClass().equals(money.getClass()); } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() Сравнение долларов и франков Валюта? XP

Методы times могут возвращать Money Money times(int mult) { return new Dollar(amount*mult); } В результате классы почти одинаковые -> хочется сделать только один класс XP

В класс Money добавим фабричный метод создания объекта Dollar: static Dollar dollar(double amount) {return new Dollar(amount);} Меняем принцип создания объекта в тесте: public void testMultiplication() { Money five=Money.dollar(5); assertEquals(Money.dollar(10),five.times(2)); assertEquals(Money.dollar(15),five.times(3)); } Осталась ошибка – метод times не определен в классе Money XP

Делаем класс Money абстрактным, добавляя в него абстрактный метод times. abstract class Money { protected double amount; … abstract Money times(int mult); } Меняем фабричный метод с точки зрения возвращаемого значения static Money dollar(double amount) {return new Dollar(amount); } XP

Делаем те же действия с классом Franc Меняем тесты public void testEquality() { assertTrue(Money.dollar(5).equals(Money.dollar(5))); assertFalse(Money.dollar(5).equals(Money.dollar(6))); assertTrue(Money.franc(5).equals(Money.franc(5))); assertFalse(Money.franc(5).equals(Money.franc(6))); assertFalse(Money.franc(5).equals(Money.dollar(5))); } XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() Сравнение долларов и франков Валюта? Нужен ли тест на умножения франков на число? XP

Добавляем метод для получения названия валюты в классы Dollar и Franc и абстрактный метод в класс Money: abstract String currency(); String currency(){ return "USD";} String currency(){ return "CHF";} Тест public void testCurrency() { assertEquals("USD",Money.dollar(1).currency()); assertEquals("CHF",Money.franc(1).currency()); } XP

Вводим символьную переменную для обозначения валюты в класс Money и переносим функцию currency полностью в класс Money abstract class Money { protected double amount; protected String currency; … String currency(){ return currency; } } Конструкторы должны инициализировать эту строку, например, Franc (double amount) { this.amount=amount; this.currency="CHF"; } XP

Конструкторы производных классов похожи -> можно инициализировать переменную currency внутри конструктора базового класса: public Money(double amount, String currency) { this.amount=amount; this.currency=currency; } Конструкторы производных классов выглядят, например, так: Franc (double amount) { super(amount,"CHF"); } Можно добавить второй параметр с обозначением валюты и передавать его конструктору базового класса XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() Сравнение долларов и франков Валюта? Нужен ли тест на умножения франков на число? XP

Функция times класса Dollar выглядит так: Money times(int mult) { return Money.dollar(amount*mult);} Вернемся к вызову конструктора: Money times(int mult) { return new Dollar(amount*mult,USD");} Строку с названием валюты можно получить из поля currency-> переносим в класс Money (класс перестает быть абстрактным) Money times(int mult){ return new Money(amount*mult,currency);} Тест не срабатывает – сравнение имен классов (один объект класса Dollar, другой – класса Money). XP

Вернемся к методам times внутри производных классов, например, в Dollar Money times(int mult) {return new Dollar(amount*mult,currency);} Тесты сработали. Добавляем тест для сравнения объектов, созданных с помощью Money и Dollar public void testDifferentClasses() { assertTrue(new Money(10,"CHF").equals(new Franc(10,"CHF"))); } Тест не сработал. XP

Меняем equals – сравнение названий валют, а не имен классов. public boolean equals(Object obj) { Money money=(Money)obj; return amount==money.amount && currency.equals(money.currency); } Тесты сработали. Снова отказываемся от методов times производных классов. Тесты сработали. XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() Сравнение долларов и франков Валюта? Нужен ли тест на умножения франков на число? XP

Производные классы имеют только конструкторы. Отказываемся от них. Методы-фабрики должны вызывать конструктор класса Money. static Money franc(double amount) { return new Money(amount,"CHF"); } Тест на равенство объектов разных классов и умножение франков можно удалить. XP

$5+10 CHF =$10, если курс обмена 2:1 $5*2=$10 amount-закрытая переменная Побочные эффекты в классе Dollar – изменение объекта Округление денежных величин equals() Равенство значению null Равенство объектов 5 CHF*2=10 CHF Дублирование Dollar/Franc Общие операции equals() Общие операции times() Сравнение долларов и франков Валюта? Нужен ли тест на умножения франков на число? $5+$5=$10 XP

Реализуем тест: public void testSimpleAddition() { Money sum=Money.dollar(5).plus(Money.dollar(5)); assertEquals(sum,Money.dollar(10)); } В класс Money добавляем функцию plus: Money plus(Money added) { return new Money(amount+added.amount,currency); } XP

Обменный курсы должен знать банк -> создаем класс Bank (в нем метод reduce для перевода денег в конкретную валюту). XP

Тест: public void testSimpleAddition() { Money five=Money.dollar(5); Money sum=five.plus(five); Bank bank=new Bank(); Money reduced=bank.reduce(sum, "USD"); assertEquals(sum,Money.dollar(10)); } В классе Bank должна быть заглушка: public class Bank { Money reduce(Money source, String to) {return Money.dollar(10); } } Метод plus возвращает Money. XP

Тесты: public void testReduceMoney() { Bank bank=new Bank(); bank.addRate("CHF","USD",2); Money result=bank.reduce(Money.franc(2), "USD"); assertEquals(Money.dollar(1),result); } public void testHashRates() { Bank bank=new Bank(); bank.addRate("CHF", "USD", 2); assertTrue(bank.rate("CHF", "USD")==2.); } XP

В классе Bank создаем хэш-таблицу: private class Pair { private String from; private String to; public Pair(String from, String to) { this.from=from; this.to=to; } public boolean equals(Object obj) { Pair p=(Pair)obj; return from.equals(p.from) && to.equals(p.to); } public int hashCode(){ return 0; } } private Hashtable rates=new Hashtable(); XP

void addRate(String from, String to, double rate) { rates.put(new Pair(from,to), new Double(rate)); } double rate(String from, String to) { Double rate=(Double)rates.get(new Pair(from,to)); return rate.doubleValue(); } XP

Делаем метод-заглушку класса Bank: Money reduce(Money source,String to) { double rate=1; if (source.currency.equals("CHF") && to.equals("USD")) rate=2.; if (source.currency.equals("USD") && to.equals("CHF")) rate=1./2; return new Money(source.amount/rate,to); } XP

Изменяем заглушку: Money reduce(Money source,String to) { double rate=1; Pair p=new Pair(source.currency,to); if (rates.containsKey(p)) rate=rate(source.currency,to); return new Money(source.amount/rate,to); } XP

Изменяем тест public void testReduceMoney() { Bank bank=new Bank(); bank.addRate("CHF","USD",2); Money result=bank.reduce(Money.franc(2), "USD"); assertEquals(Money.dollar(1),result); result=bank.reduce(Money.dollar(2), "USD"); assertEquals(result,Money.dollar(2)); result=bank.reduce(Money.dollar(2), "CHF"); assertEquals(result,Money.franc(4)); } Тест не работает, так как если курса нет, то в хэш-таблице ничего не будет найдено. XP

Добавлять надо два курса void addRate(String from, String to, double rate) { rates.put(new Pair(from,to), new Double(rate)); rates.put(new Pair(to,from), new Double(1/rate)); } XP