Краят на модула
Това е последният урок от Модул 1. Няма нови понятия — има една задача, която ги събира всичките: интерфейс, няколко класа, които го реализират различно, конструктори, капсулация и полиморфизъм.
Ключово
Триъгълник може да се зададе по три различни начина. Интерфейсът позволява програмата да не се интересува кой от тях е използван — тя иска само периметър и лице.
Интерфейсът ITriangle
От предишния урок вече имаме интерфейса и първата му реализация. Ето ги отново, защото всичко тук стъпва върху тях:
interface ITriangle
{
double Perimeter();
double Face();
}Класът Triangle1 описва триъгълник, зададен с трите си страни. Периметърът е P = a + b + c, а лицето — по формулата на Херон.
class Triangle1 : ITriangle
{
private double a, b, c;
public Triangle1(double a, double b, double c)
{ this.a = a; this.b = b; this.c = c; }
public double Perimeter() { return a + b + c; }
public double Face()
{
double p = this.Perimeter() / 2;
return Math.Sqrt(p * (p - a) * (p - b) * (p - c));
}
}Бележка
Забележи private пред страните. Отвън се вижда само това, което интерфейсът обещава — Perimeter() и Face(). Точно това е капсулацията от урок 16.
Задача 1 — Triangle2 по две страни и ъгъла между тях
Триъгълникът е зададен със страни a, b и ъгъл α между тях. Нека a е страната AB, b — страната AC, c — страната BC, h — височината CH, а a₁ и a₂ — двете части AH и HB на AB.
- От правоъгълния триъгълник AHC: h = b·sin α, а лицето е S = ab·sin α / 2.
- За периметъра трябва страната c. По Питагор от AHC: a₁ = √(b² − h²).
- Тогава a₂ = a − a₁, и още веднъж Питагор за BHC дава c = √(a₂² + h²).
Внимание
Тригонометричните функции на класа Math искат ъглите да се задават не в градуси, а в радиани (360° = 2π радиана). Ако подадеш 90 вместо π/2, резултатът няма да е грешен видимо — просто ще е друг триъгълник.
Задача 2 — недопустими данни
Опитай да зададеш за страните на триъгълник стойностите 1, 5 и 8. Какво прави програмата?
Такъв триъгълник не съществува: 1 + 5 = 6, което е по-малко от 8. Това е неравенството на триъгълника — всяка страна трябва да е по-малка от сбора на другите две. Под корена на Херон се получава отрицателно число, а Math.Sqrt от отрицателно число връща NaN (Not a Number).
Внимание
Програмата не гърми — тя тихо извежда NaN. Това е по-лошо от грешка: изглежда, че е работила. Класът трябва сам да се защити.
Най-простата защита е проверка в конструктора, която отказва да създаде невъзможен обект:
public Triangle1(double a, double b, double c)
{
if (a <= 0 || b <= 0 || c <= 0)
throw new ArgumentException("Страните трябва да са положителни.");
if (a + b <= c || a + c <= b || b + c <= a)
throw new ArgumentException("Такъв триъгълник не съществува.");
this.a = a; this.b = b; this.c = c;
}Задача 3 — Triangle3 по страна и два прилежащи ъгъла
Проектирай и създай клас Triangle3 за триъгълници, зададени със страна и два прилежащи ъгъла. Указание: използвай синусовата теорема.
| Клас | Задава се с | Ключова формула |
|---|---|---|
| Triangle1 | три страни | Херон |
| Triangle2 | две страни и ъгъл между тях | S = ab·sin α / 2 |
| Triangle3 | страна и два прилежащи ъгъла | синусова теорема |
И трите реализират един и същ интерфейс. Затова могат да се сложат в един масив от тип ITriangle и да се обходят с един цикъл — това е полиморфизмът в действие.
Контрол и оценка
Задачи
1. Реализирай Triangle2 и Triangle3 и ги провери с триъгълник, който познаваш — например 3-4-5.
2. Добави защитата от задача 2 и към трите класа. Кои стойности са недопустими за Triangle3?
3. Напиши програма, която създава по един обект от трите класа за един и същ триъгълник и проверява, че и трите дават еднакви периметър и лице.
Какво трябва да запомниш
- Един интерфейс, няколко реализации — програмата работи с договора, не с конкретния клас.
Mathиска ъгли в радиани: градуси · π / 180.Math.Sqrtот отрицателно число даваNaN, без да гръмне — тихите грешки са най-опасните.- Неравенство на триъгълника: всяка страна е по-малка от сбора на другите две.
- Проверката за валидност е работа на конструктора — обект, който не може да съществува, не бива да се създава.