Лого на 91. НЕГ „Проф. Константин Гълъбов“

Модул 1 · Урок 29

Още за обектно-ориентирания подход

Обобщение на Модул 1: интерфейсът ITriangle и три класа, които го реализират по различен начин. Защита от недопустими данни и неравенството на триъгълника.

Краят на модула

Това е последният урок от Модул 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₂ = aa₁, и още веднъж Питагор за 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, без да гръмне — тихите грешки са най-опасните.
  • Неравенство на триъгълника: всяка страна е по-малка от сбора на другите две.
  • Проверката за валидност е работа на конструктора — обект, който не може да съществува, не бива да се създава.