Реалізація концепцій “спадковості” та “поліморфізму” в об’єктно-орієнтованому програмуванні на прикладі побудови двох класів. Інтерфейси ICloneable, IEquatable

C# – Контрольна робота. Реалізація концепцій “спадковості” та “поліморфізму” в об’єктно-орієнтованому програмуванні на прикладі побудови двох класів. Інтерфейси ICloneable, IEquatable

 

Зміст


Умова задачі

У розроблених класах необхідно реалізувати такі концепції ООП як “спадковість” та “поліморфізм“.

Потрібно описати базовий клас (клас-предок) та успадкувати (наслідувати) від нього. Частину функціональності класів треба реалізувати з використанням властивостей.

Кожний клас повинен містити реалізацію принаймні:

  • двох конструкторів;
  • двох методів;
  • двох властивостей;
  • двох інтерфейсів.

Необхідно перевизначити операції над об’єктами класів.

Створити клас, що визначає коло на площині. Користуючись розробленими класами знайти площу кола.

Реалізувати інтерфейси ICloneable, IEquatable.


Математична постановка задачі

На рисунку 1 зображене коло на площині.

02_02_00_017_01_

Рис. 1. Зображення кола на площині

Як видно з рисунку 1, для позначення кола на площині потрібно:

  • координати (x, y) точки середини кола;
  • радіус кола R.

Площа круга обчислюється за формулою:

02_02_00_017_formula

де S – площа круга; R – радіус кола; π – константа, яка дорівнює 3.1415.


Виконання

1. Створення нового проекту.

Завантажити Microsoft Visual Studio. Створити новий проект як Windows Forms Application. Приклад створення нового проекту наведено тут.

Автоматично буде створена нова форма додатку.


2. Розміщення елементів управління на формі.

Розмістити на формі такі елементи управління (рисунок 2):

– два елементи управління типу Label. Автоматично буде створено об’єкти з іменами label1 та label2;

– елемент управління типу TextBox. Створюється новий об’єкт з іменем textBox1;

– елемент управління типу Button. Створюється об’єкт з іменем button1.

02_02_00_017_02_

Рис. 2. Розміщення елементів управління на формі


3. Налаштування властивостей елементів управління.

Налаштувати такі властивості елементів управління (рисунок 3):

– в елементі управління label1 властивість Text = “R = “;

– в елементі управління label2 властивість Text = “S = “;

– в елементі управління button1 властивість Text = “Обчислити“;

– в елементі управління Form1 властивість Text = “Площа круга“.

02_02_00_017_03u

Рис. 3. Форма додатку після налаштування елементів управління

Після налаштування форми потрібно зайнятися побудовою класів.


4. Класи, що необхідні для розв’язку задачі.

Згідно з умовою задачі, отримується два класи:

– клас Point, що відображає точку на площині. Цей клас повинен бути базовим;

– клас Circle, що відображає коло. Цей клас повинен успадкувати дані та методи класу Point (згідно з умовою задачі).

У даній задачі клас Point називається базовим, а клас Circle – похідним.

Отже, виникає ієрархія з 2-х класів. Схема ієрархії класів та відображення даних (полів) в класах зображена на рисунку 4.

02_02_00_017_04u

Рис. 4. Ієрархія класів згідно з умовою задачі

По ходу розв’язку задачі в класи будуть вноситись зміни: властивості та методи.

Опишемо клас Point, що містить тільки дані. На мові C# лістинг класу Point буде наступний:

class Point
{
    // поля класу оголошені як protected
    protected float x; // координата x точки
    protected float y; // координата y точки
}

У класі Point дані класу описуються як protected. Це означає, що ці дані є видимі у похідних класах і невидимі ззовні (приховані для доступу через об’єкт класу).

Для доступу до даних будуть використовуватись властивості та спеціальні методи.

Так само створюється клас Circle. Поки що лістинг класу Circle наступний:

class Circle:Point // успадковує дані класу Point
{
    // поля класу
    private float R; // радіус кола
}

В описі класу Circle, початок рядка

class Circle:Point

означає, що клас Circle успадковує дані та методи класу Point.

Таким чином, на даний момент, в класі Circle є доступні три поля:

– поле x з успадкованого класу Point;

– поле y з успадкованого класу Point;

– поле R, що є внутрішнім полем класу Circle.


5. Реалізація конструкторів класу Point.

Згідно з умовою задачі, кожен з класів повинен містити мінімум два конструктори.

Послідовно в текст класу Point потрібно додати два конструктори. Перший конструктор без параметрів ініціалізує дані нульовими значеннями.

Другий конструктор – параметризований. Цей конструктор отримує 2 параметри і встановлює нові значення для внутрішніх змінних x та y.

Нижче наведено текст програмного коду обох конструкторів:

// конструктор 1 - без параметрів
public Point()
{
    x = 0f; // занулення значень координат
    y = 0f;
}

// конструктор 2 - з двома параметрами
public Point(float nx, float ny)
{
    x = nx;
    y = ny;
}

Слід звернути увагу, що конструктори мають тип доступу public, тому що вони викликаються ззовні при створенні об’єкту класу.


6. Реалізація конструкторів класу Circle.

Так само потрібно додати два конструктори в клас Circle.

// конструктор 1 - ініціалізує поля нульовими значеннями
public Circle()
{
    x = 0f; // 0f - означає, що це значення має тип float
    y = 0f;
    R = 0f;
}

// конструктор 2 - з трьома параметрами
public Circle(float nx, float ny, float nR)
{
    x = nx;
    y = ny;
    R = nR;
}


7. Реалізація методів класу Point.

Згідно з умовою задачі, в кожному класі повинно бути реалізовано два методи. Реалізуємо методи, які виконують такі дії:

  • метод GetPoint(), що повертає точку типу Point;
  • метод SetXY(), що встановлює нові значення внутрішніх змінних класу Point.

Тип доступу для методів вибрано як public.

Лістинг методів наступний.

public Point GetPoint()
{
    Point p; // описується змінна (об'єкт), для якої пам'ять ще не виділена
    p = new Point(x,y); // виділяється пам'ять, створюється новий екземпляр класу
    return p;
}

// метод, що встановлює нові значення внутрішніх змінних
public void SetXY(float nx, float ny)
{
    x = nx;
    y = ny;
}


8. Реалізація методів класу Circle.

Подібним чином створюються методи класу Circle. У класі Circle реалізуються два методи. Перший метод GetCircle() повертає об’єкт (з виділенням пам’яті) типу Circle.

Другий метод SetXYR() встановлює нові значення внутрішніх змінних. Цей метод отримує вхідними 3 параметри (координати x, y та радіус R кола). У методі продемонстровано використання ключового слова this для доступу до полів класу. У цьому випадку імена локальних змінних-параметрів співпадають з іменами полів класу і ховають їх видимість.

Лістинг методів наступний:

// методи класу Circle згідно з умовою задачі
// метод, що отримує новий екземпляр класу типу Circle
public Circle GetCircle()
{
    Circle c;
    c = new Circle(x, y, R);
    return c;
}

// метод, що встановлює нові значення у внутрішні поля класу Circle
public void SetXYR(float x, float y, float R)
{
    // приклад використання ключового слова this
    // у внутрішню змінну x класу заноситься значення локальної змінної x методу SetXYR()
    this.x = x;
    // так само заповнюються внутрішні змінні y та R класу Circle
    this.y = y;
    this.R = R;
}


9. Приклади використання конструкторів та методів класів Point та Circle.

Наведемо декілька прикладів використання конструкторів та методів класів Point та Circle.

Демонстрація методів GetPoint() та SetXY():

// клас Point
// виклик конструктора без параметрів класу Point()
Point p = new Point();
Point p1 = null, p2 = null;
p1 = new Point(4.5f, 3.2f); // виклик конструктора з двома параметрами
p2 = p1.GetPoint();
p2.SetXY(3.3f, -2.8f); // встановити нові значення

// клас Circle
Circle c = new Circle(); // конструктор без параметрів
Circle c1, c2;
c1 = new Circle(3.3f, -2.8f, 12f); // виділення пам'яті
c2 = c1.GetCircle(); // метод GetCircle()
c2.SetXYR(3.8f, -1.9f, 8f); // метод SetXYR()


10. Вихідний код класів.

На даний момент класи Point та Circle мають такий вигляд:

// опис класу Point
class Point
{
    // поля класу оголошені як protected
    protected float x; // координата x точки
    protected float y; // координата y точки

    // конструктор 1 - без параметрів
    public Point()
    {
        x = 0f;
        y = 0f;
    }

    // конструктор 2 - з двома параметрами
    public Point(float nx, float ny)
    {
        x = nx;
        y = ny;
    }

    public Point GetPoint()
    {
        Point p; // описується змінна (об'єкт), для якої пам'ять ще не виділена
        p = new Point(x,y); // виділяється пам'ять, створюється новий екземпляр класу
        return p;
    }

    // метод, що встановлює нові значення внутрішніх змінних
    public void SetXY(float nx, float ny)
    {
        x = nx;
        y = ny;
    }
}

// опис класу Circle
class Circle:Point // успадковує дані класу Point
{
    // поля класу
    private float R; // радіус кола

    // конструктор 1 - ініціалізує поля нульовими значеннями
    public Circle()
    {
        x = 0f;
        y = 0f;
        R = 0f;
    }

    // конструктор 2 - з трьома параметрами
    public Circle(float nx, float ny, float nR)
    {
        x = nx;
        y = ny;
        R = nR;
    }

    // методи класу Circle згідно з умовою задачі
    // метод, що отримує новий екземпляр класу типу Circle
    public Circle GetCircle()
    {
        Circle c; // створюється новий об'єкт типу клас Circle
        c = new Circle(x, y, R); // виділяється пам'ять для об'єкту c, створюється екземпляр класу
        return c;
    }

    // метод, що встановлює нові значення у внутрішні поля класу Circle
    public void SetXYR(float x, float y, float R)
    {
        // приклад використання ключового слова this
        this.x = x; // у внутрішню змінну x класу заноситься значення локальної змінної x методу SetXYR()
        this.y = y; // так само заповнюються внутрішні змінні y та R класу Circle
        this.R = R;
    }
}


11. Реалізація властивостей класу Point.

Наступним кроком потрібно створити дві властивості класу Point.

Перша властивість повертає або встановлює значення координат точки x. Друга властивість повертає/встановлює значення координати y.

Ім’я першої властивості XX. Ім’я другої властивості YY.

Лістинг властивостей XX та YY наступний:

// властивість, що повертає/встановлює координату x
public float XX
{
    get { return x; }
    set { x = value; }
}

// властивість, що повертає/встановлює координату y
public float YY
{
    get { return y; }
    set { y = value; }
}

Після такого опису властивості XX та YY можна використовувати. Нижче наведено приклад використання властивостей XX та YY.

...

Point p = new Point(5.2f, 6.35f); // створення об'єкту типу Point
float x,y;

x = p.XX; // x = 5.2
y = p.YY; // y = 6.35

// перевизначити значення
p.XX = 2.33f;
p.YY = -3.8f;

x = p.XX; // x = 2.33
y = p.YY; // y = -3.8

...


12. Реалізація властивостей класу Circle.

Аналогічним чином описуються властивості класу Circle. Перша властивість читає/встановлює значення радіусу R. Друга властивість читає/встановлює значення точки, що є центром кола (клас Point).

// властивості класу Circle
// властивість, що повертає значення радіусу кола R
public float RR
{
    get { return R; }
    set { R = value; }
}

// властивість, що повертає значення точки типу Point, що є центром кола
public Point PP
{
    get
    {
        Point p;
        p = new Point(x, y);
        return p;
    }

    set
    {
        x = value.XX;
        y = value.YY;
    }
}

У нижченаведеному лістингу описується приклад використання властивостей PP та RR у програмі.

// створення об'єкту, в якому значення полів x = 5.5; y = -2.3; R = 12.8
Circle c = new Circle(5.5f, -2.3f, 12.8f);
float x, y, R;

// доступ до властивості PP класу Circle
x = c.PP.XX; // x = 5.5
y = c.PP.YY; // y = -2.3

// доступ до властивості RR
R = c.RR; // R = 12.8
c.RR = -20.85f;


13. Реалізація методів інтерфейсу ICloneable в класах.

Якщо реалізувати інтерфейс ICloneable, то можна забезпечити глибоке копіювання об’єктів.

У нижченаведеному прикладі здійснюється поверхневе копіювання об’єктів:

Point p1 = new Point(5.3f, -6.8f);
Point p2;

// поверхневе копіювання
p2 = p1; // обидва об’єкти вказують на одну ділянку пам’яті

Інтерфейс ICloneable представляє один метод для реалізації. Цей метод називається Clone(). Цей метод потрібно реалізувати в класах Point та Circle. Реалізація методу працює за однаковим принципом.

Перш за все потрібно змінити заголовок класу Point. Замість тексту

class Point

потрібно набрати

class Point:ICloneable

Це означає, що в класі Point потрібно реалізувати єдиний метод Clone(). Лістинг методу наступний:

// реалізація методу Clone() в інтерфейсі ICloneable
public object Clone()
{
    Point p = new Point(x, y);
    return p;
}

Так як клас Circle успадковує клас Point, який успадковує інтерфейс ICloneable, то в класі Circle також можна реалізувати метод Clone().

// Реалізація інтерфейсу ICloneable
public object Clone()
{
    Circle c = new Circle();
    return c;
}

Приклад використання методу Clone().

Point p1 = new Point(5.2f, 6.35f); // створення об'єкту
Point p2;

// глибоке копіювання, тому що реалізовано метод Clone()
p2 = (Point)p1.Clone(); // для p2 виділяється окремо пам'ять

// клас Circle
Circle c1 = new Circle(3.2f, -8.3f, 11f);
Circle c2 = null;
c2 = (Circle)c1.Clone(); // для c2 виділяється оперативна пам'ять


14. Реалізація методів інтерфейсу IEquatable.

Інтерфейс IEquatable реалізується в тих класах, де потрібно визначити порядок порівняння двох об’єктів на рівність їх значень. У цьому інтерфейсі визначається тільки один метод Equals(). Цей метод повертає значення true, якщо значення викликаючого об’єкту є рівним значенню іншого об’єкта, що є параметром в методі Equals().

У нашому випадку, реалізуємо метод Equals(), який порівнює на рівність значення змінних x та y.

Лістинг методу Equals() для класу Point наступний:

// реалізація методу Equals() з інтерфейсу IEquatable
public bool Equals(Point p2)
{
    if ((this.x == p2.x) && (this.y == p2.y))
    {
        return true;
    }
    else
        return false;
}

Лістинг методу Equals() для класу Circle наступний:

// Реалізація методу Equals() з інтерфейсу IEquatable
public bool Equals(Circle c2)
{
    if ((this.x == c2.x) && (this.y == c2.y) && (this.R == c2.R))
        return true;
    else
        return false;
}

У програмі метод Equals() для класів можна використовувати наступним чином:

// демонстрація методу Equals() для класу Point
Point p1 = new Point(3f, -5.5f);
Point p2;
bool f;

p2 = (Point)p1.Clone();
f = p1.Equals(p2); // ff = true

// демонстрація методу Equals() для класу Circle
Circle c1 = new Circle(3.2f, -8.3f, 11f);
Circle c2 = new Circle(3.2f, -8.3f, 11f);
f = c1.Equals(c2); // f = true


15. Реалізація методу обчислення площі круга в класі Circle.

Назва методу – GetSquare(). Для обчислення площі круга потрібно мати тільки радіус R. Радіус отримується з внутрішньої змінної R. Результат обчислення є тип float.

В текст класу Circle потрібно додати наступний метод:

// Метод, що обчислює площу круга
public float GetSquare()
{
    const float pi = 3.1415f;
    float s;
    s = pi * R * R;
    return s;
}


16. Скорочений лістинг класу Point.

Скорочений лістинг класу Point наступний (деталі реалізації описуються в попередніх пунктах):

class Point:ICloneable,IEquatable<Point>
{
    // поля класу оголошені як protected
    protected float x; // координата x точки
    protected float y; // координата y точки

    // конструктор 1 - без параметрів
    public Point() { ... }

    // конструктор 2 - з двома параметрами
    public Point(float nx, float ny) { ... }

    // метод, що повертає точку з координатами
    public Point GetPoint() { ... }

    // метод, що встановлює нові значення внутрішніх змінних
    public void SetXY(float nx, float ny) { ... }

    // властивість, що повертає/встановлює координату x
    public float XX
    {
        get { ... }
        set { ... }
    }

    // властивість, що повертає/встановлює координату y
    public float YY
    {
        get { ... }
        set { ... }
    }

    // реалізація методу Clone() в інтерфейсі ICloneable
    public object Clone() { ... }

    // реалізація методу Equals() з інтерфейсу IEquatable
    public bool Equals(Point p2) { ... }
}


17. Скорочений лістинг класу Circle.

Нижче наведено лістинг класу Circle, в якому приховані деталі реалізації. Реалізація методів, властивостей, конструкторів описується в попередніх пунктах.

class Circle:Point // успадковує дані класу Point
{
    // поля класу
    private float R; // радіус кола

    // конструктор 1 - ініціалізує поля нульовими значеннями
    public Circle() { ... }

    // конструктор 2 - з трьома параметрами
    public Circle(float nx, float ny, float nR) { ... }

    // методи класу Circle згідно з умовою задачі
    // метод, що отримує новий екземпляр класу типу Circle
    public Circle GetCircle() { ... }

    // метод, що встановлює нові значення у внутрішні поля класу Circle
    public void SetXYR(float x, float y, float R) { ... }

    // властивості класу Circle
    // властивість, що повертає значення радіусу кола R
    public float RR
    {
        get { ... }
        set { ... }
    }

    // властивість, що повертає значення точки типу Point, що є центром кола
    public Point PP
    {
        get { ... }
        set { ... }
    }

    // Реалізація інтерфейсу ICloneable
    public object Clone() { ... }

    // Реалізація методу Equals() з інтерфейсу IEquatable
    public bool Equals(Circle c2) { ... }

    // Метод, що обчислює площу круга
    public float GetSquare() { ... }
}


18. Програмування обробника події кліку на кнопці “Обчислити“.

Обчислення площі круга здійснюється в момент, коли користувач зробить клік на кнопці “Обчислити“. Лістинг обробника події кліку на кнопці “Обчислити” наступний:

private void button1_Click(object sender, EventArgs e)
{
    Circle c = new Circle();
    float s;

    // заповнити значення R
    c.RR = (float)Double.Parse(textBox1.Text);

    // порахувати площу круга
    s = c.GetSquare();
    label2.Text = "S = " + s.ToString();
}

Результат роботи програми зображено на рисунку 5.

02_02_00_017_05u

Рис. 5. Виконання програми


Схожі теми