Какво минахме дотук
Това е обобщителният урок на темата „Обектно-ориентиран подход“. Няма нови понятия — има един клас, който ще довършим както трябва.
| Понятие | Какво е | От кой урок |
|---|---|---|
| Обект | Компютърен модел на реален или абстрактен обект | 14 |
| Клас | Тип, обединяващ атрибути и методи на еднотипни обекти | 14, 15 |
| Атрибут | Характеристика, съхранена в паметта на обекта | 15, 16 |
| Метод | Функция, която извършва обработка над обекта | 17 |
| Конструктор | Метод с името на класа, който създава инстанцията | 18 |
| Референция | Стойността на променлива от клас — адрес, не обект | 19 |
Ключово
Класът Rational го влачим от урок 8. Тогава беше две цели числа и купчина формули. Сега ще стане нещо, което наистина може да се ползва.
Задача 1 — съкратени дроби
При изпълнението на достатъчно примери на програмата Rational ще забележиш, че пресметнатите резултати са необичайни. Получените дроби често имат числител и знаменател, които се делят на някакво число. Такава форма на правилната дроб се нарича несъкратена.
Обикновено е дробите да се показват в съкратен вид. За целта числителят и знаменателят трябва да се разделят на най-големия им общ делител — НОД(num, denum). Алгоритъмът на Евклид вече го знаеш от урок 12; сега го оформяме като метод на класа:
private int GCD(int a, int b)
{
int tmp, r;
if (a < b) { tmp = a; a = b; b = tmp; }
while (b != 0)
{
r = a % b; a = b; b = r;
}
return a;
}Бележка
Забележи private вместо public. Този метод е вътрешна кухня на класа — потребителят му няма работа с него. Точно за това служи капсулацията от урок 16.
Сега методът за събиране добива вида:
public void Add(Rational r)
{
this.num = this.num * r.denum + r.num * this.denum;
this.denum = this.denum * r.denum;
int g = GCD(num, denum);
this.num = this.num / g;
this.denum = this.denum / g;
}Модифицирай по същия начин и останалите методи за извършване на аритметичните операции.
Задача 2 — нормализирано извеждане
Едно друго необичайно нещо при извеждане на дробните числа е извеждането на целите числа като дроби със знаменател 1, както и извеждането на дробите, чиято стойност е 0, със знаменател. Добави в класа метод, който нормализира тези случаи:
public void normPrint()
{
if (this.denum == 1) Console.WriteLine(this.num);
else if (this.num == 0) Console.WriteLine("0");
else Console.WriteLine(this.num + "/" + this.denum);
}| Дроб | Print() | normPrint() |
|---|---|---|
| 5/1 | 5/1 | 5 |
| 0/7 | 0/7 | 0 |
| 3/4 | 3/4 | 3/4 |
Контрол и оценка
Задача 1 — извеждане в десетичен вид
При създаването на класа Rational предвидихме атрибут, който да съхранява правилната дроб и като десетична. Добави в класа метод public void decPrint(), който извежда инстанция на класа във вид на десетична дроб, с аргумент броя на цифрите след десетичната точка.
Съвет
Указание: използвай метода Math.Round(), за да „изрежеш“ ненужните цифри. Внимавай с целочисленото деление — num / denum при два int дава цяло число.
Още за проверка
1. Модифицирай всички аритметични методи да съкращават резултата. Компилирай и провери с различни примери.
2. Модифицирай програмата Rational така, че да използва метода за извеждане на дробите в нормализиран вид.
3. Какво се случва, ако някой създаде дроб със знаменател 0? Как би защитил класа от това?
Какво трябва да запомниш
- Вътрешните помощни методи се правят
private— потребителят на класа не бива да ги вижда. - Съкращаването на дроб е деление на числителя и знаменателя на НОД(num, denum).
- Един добър клас не само смята вярно, а и показва резултата в очаквания вид — оттам са
normPrintиdecPrint. - При
int / intв C# резултатът е цяло число. За десетичен вид поне единият операнд трябва да е дробен. - Формулите не изчезват в ООП — те се преместват там, където им е мястото: вътре в класа.