#set text(size: 1.3em)

#show raw.where(block: false): box.with(
  fill: luma(240),
  inset: (x: 3pt, y: 0pt),
  outset: (y: 3pt),
  radius: 2pt,
)

#show raw.where(block: true): block.with(
  fill: luma(240),
  inset: 10pt,
  radius: 4pt,
)
    
// title
    
#align(center)[Санкт-Петербургский национальный исследовательский университет информационных технологий, механики и оптики]
\
\
\
#align(center)[Факультет инфокоммуникационных технологий]
#align(center)[Направление подготовки 11.03.02]
\
\
#align(center)[Лабораторная работа №7]
#align(center)[Создание иерархии классов]
\
\
\ //#align(center)[Вариант 19]
\
\
\
\
\
\
\
#align(right)[Выполнил:]
#align(right)[Дощенников Никита Андреевич]
#align(right)[Группа: К3221]
#align(right)[Проверил:]
#align(right)[Иванов Сергей Евгеньевич]
\
\
#align(center)[Санкт-Петербург]
#align(center)[2025]

#pagebreak()
    
=== Цель работы: 

Изучение наследования как важного элемента объектно-ориентированного программирования и приобретение навыков реализации иерархии классов.

=== Упражнение 1. Реализация наследования классов.

В этом упражнении я использовал наследование для построения иерархии между классами, имеющих отношение типа "является". Вы добавите новый класс `Item`, который будет являться базовым для уже имеющегося класса `Book`.

```cs
using System; 

abstract class Item 
{
    protected long invNumber;
    protected bool taken;

    public Item(long invNumber, bool taken)
    {
        this.invNumber = invNumber;
        this.taken = taken;
    }

    public Item()
    {
        this.taken = true;
    }

    public bool IsAvailable()
    {
        return taken;
    }

    public long GetInvNumber()
    {
        return invNumber;
    }

    private void Take()
    {
        taken = false;
    }

    public void TakeItem()
    {
        if (this.IsAvailable())
            this.Take();
    }


    abstract public void Return();

    public virtual void Show()
    {
        Console.WriteLine("Состояние единицы хранения:\n Инвентарный номер: {0}\n Наличие: {1}", invNumber, taken);
    }
}
```

```cs 
using System;

class Book : Item
{
    private String author;
    private String title;
    private String publisher;
    private int pages;
    private int year;
    private bool returnSrok;

    private static double price = 9;

    static Book()
    {
        price = 10;
    }

    public Book()
    {

    }


    public Book(String author, String title, String publisher, int pages, int year, long invNumber, bool taken) : base (invNumber, taken)
    {
        this.author = author;
        this.title = title;
        this.publisher = publisher;
        this.pages = pages;
        this.year = year;
    }

    public Book(String author, String title)
    {
        this.author = author;
        this.title = title;
    }

    public void SetBook(String author, String title, String publisher, int pages, int year)
    {
        this.author = author;
        this.title = title;
        this.publisher = publisher;
        this.pages = pages;
        this.year = year;
    }

    public static void SetPrice(double price)
    {
        Book.price = price;
    }


    public override void Show()
    {
        Console.WriteLine("\nКнига:\n Автор: {0}\n Название: {1}\n Год издания: {2}\n {3} стр.\n Стоимость аренды: {4}", author, title, year, pages, Book.price);
        base.Show();
    }


    public double PriceBook(int s)
    {
        double cost = s * price;
        return cost;
    }

    public void ReturnSrok()
    {
        returnSrok = true;
    }

    public override void Return()
    {
        taken = returnSrok;
    }
}
```

Тесты: 

```cs 
public static void Main(string[] args)
{
    Item item1 = new Item();
    item1.Show();
}
```

=== Упражнение 2. Использование конструкторов.

В этом упражнении я определил конструкторы в базовом и в производном классах и реализуете их выполнение в обоих классах с помощью ключевого слова `base`, которое позволяет вызвать конструктор базового класса.

```cs
using System;

class Magazine : Item 
{
    private String volume;
    private int number;
    private String title;
    private int year;

    public Magazine(String volume, int number, String title, int year, long invNumber, bool taken) : base(invNumber, taken)
    {
        this.volume = volume;
        this.number = number;
        this.title = title;
        this.year = year;
    }

    public Magazine()
    {}

    public override void Show()
    {
        Console.WriteLine("\nЖурнал:\n Том: {0}\n Номер: {1}\n Название: {2}\n Год выпуска: {3}", volume, number, title, year);
        base.Show();
    }


    public override void Return()
    {
        taken = true;
    }

}
```

Тесты:

```cs
public static void Main(string[] args)
{
        Book b2 = new Book("Толстой Л. Н.", "Война и мир", "Наука и жизнь", 1234, 2013, 101, true);

        b2.Show();
        b2.TakeItem();
        b2.Show();

        Magazine mag1 = new Magazine("О природе", 5, "Земля и мы", 2014, 1235, true);
        mag1.Show();
}
```

Пример: 

#align(center)[#image("assets/1.png")]

=== Упражнение 3. Переопределение методов.

В этом упражнении я реализовал механизм полиморфизма с помощью виртуальных методов и их переопределения в производных классах.

```cs
public static void Main(string[] args)
{
    Book b2 = new Book("Толстой Л. Н.", "Война и мир", "Наука и жизнь", 1234, 2013, 101, true);

    b2.Show();
    b2.TakeItem();
    b2.Show();


    Magazine mag1 = new Magazine("О природе", 5, "Земля и мы", 2014, 1235, true);
    mag1.Show();

    Console.WriteLine("\n Тестирование полиформизма");
    Item it;

    it = b2;
    it.TakeItem();
    it.Return();
    it.Show();

    it = mag1;
    it.TakeItem();
    it.Return();
    it.Show();
}
```

Пример: 

#align(center)[#image("assets/2.png")]

=== Упражнение 4. Применение абстрактного класса и абстрактных методов. 

В этом упражнении я сделал базовый класс и один из его методов абстрактным.

Тесты и примеры совпадают с предыдущим упражнением.

=== Упражнение 5. Реализации модели включения.

В этом упражнении я реализовал отношение "имеет", известное под названием модели включения или агрегации.

```cs
using System;

class Point
{
    private double x;
    private double y;

    public Point(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    public Point ()
    {}

    public void Show()
    {
        Console.WriteLine("Точка с координатами: ({0}, {1})", x, y);
    }

    public double Dlina(Point p)
    {
        double Dl = Math.Sqrt((this.x - p.x) * (this.x - p.x) + (this.y - p.y) * (this.y - p.y));
        return Dl;
    }

    public override string ToString()
    {
        string ss = x + " ; " + y;
        return ss;
    }
}
```

```cs
using System;

class Line
{
    private Point pStart;
    private Point pEnd;

    public Line(Point pStart, Point pEnd)
    {
        this.pStart = pStart;
        this.pEnd = pEnd;
    }

    public Line()
    { }

    public void Show()
    {
        Console.WriteLine("Отрезок с координатами: ({0}) - ({1})", pStart, pEnd);
    }

    public double DlinL()
    {
        return pStart.Dlina(pEnd);
    }
}
```

Тесты: 

```cs
using System;

public class Program
{
    public static void Main(string[] args)
    {
        Point p1 = new Point();
        p1.Show();
        Point p2 = new Point(12, 13);
        p2.Show();

        Line line = new Line(p1, p2);
        line.Show();

        double dtr = line.DlinL();
        Console.WriteLine("Длина отрезка " + dtr);
    }
}
```

Примеры: 

#align(center)[#image("assets/3.png")]

=== Упражнение 6. Реализация отношения ассоциации между классами.

В этом упражнении я создал класс, моделирующий игральную кость и класс игрока, который связан с классом игры отношением ассоциации - каждый отдельный сеанс игры связан с конкретным игроком, бросающим кубик. 

```cs
using System;

class IgralnayaKost 
{
    Random r;

    public IgralnayaKost()
    {
        r = new Random();
    }

    public int random()
    {
        int res = r.Next(6) + 1;
        return res;
    }
}
```

```cs
using System;

class Gamer
{
    string Name;
    IgralnayaKost seans;

    public Gamer(string name)
    {
        Name = name;
        seans = new IgralnayaKost();
    }

    public int SeansGame()
    {
        return seans.random();
    }

    public override string ToString()
    {
        return Name;
    }
}
```

Тесты: 

```cs
public static void Main(string[] args)
{
    Gamer g1 = new Gamer("Niko");

    for (int i = 1; i <= 6; i++)
    {
        Console.WriteLine("Выпало количество очков {0} для игрока {1}", g1.SeansGame(), g1.ToString());
    }
}
```

Примеры:

#align(center)[#image("assets/4.png")]

=== Упражнение 7. Реализация прогрессии.

В этом упражнении я определил абстрактный класс `Progression`, описывающий прогрессии. В этом классе определил абстрактный метод `GetElement` с целочисленным параметром `k`, возвращающий элемент прогрессии. Определил два производных класса `ArithmeticProgression` и `GeometricProgression`, описывающие арифметическую и геометрическую прогрессии. В каждом из классов определил конструктор, задающий параметры прогрессии и перегрузил унаследованный метод `GetElement`.

```cs
using System;

abstract class Progression
{
    public abstract int GetElement(int k);
    public abstract int Sum(int n);
}
```

```cs
using System;

class ArithmeticProgression : Progression
{
    private int a0;
    private int b;

    public ArithmeticProgression(int a0, int b)
    {
        this.a0 = a0;
        this.b = b;
    }

    public override int GetElement(int k)
    {
        return a0 + (k - 1) * b;
    }

    public override int Sum(int n)
    {
        return (2 * a0 + (n - 1) * b) * n / 2;
    }
}
```

```cs
using System;

class GeometricProgression : Progression
{
    private int p0;
    private int q;

    public GeometricProgression(int p0, int q)
    {
        this.p0 = p0;
        this.q = q;
    }

    public override int GetElement(int k)
    {
        return p0 * (int)Math.Pow(q, k - 1);
    }

    public override int Sum(int n)
    {
        if (q == 1) return p0 * n;
        return p0 * (int)((Math.Pow(q, n) - 1) / (q - 1));
    }
}
```

Тесты: 

```cs
public static void Main(string[] args)
{
    Progression arith = new ArithmeticProgression(2, 3);
    Progression geom = new GeometricProgression(2, 2);

    Console.WriteLine("Арифметическая прогрессия:");
    Console.WriteLine("5-й элемент = " + arith.GetElement(5));
    Console.WriteLine("Сумма 5 элементов = " + arith.Sum(5));

    Console.WriteLine("\nГеометрическая прогрессия:");
    Console.WriteLine("5-й элемент = " + geom.GetElement(5));
    Console.WriteLine("Сумма 5 элементов = " + geom.Sum(5));
}
```

Пример: 

#align(center)[#image("assets/5.png")]

=== Выводы.

В ходе проделанной работе я изучил наследование как важный элемент объектно-ориентированного программирования и приобрел навыки реализации иерархии классов.

=== Code review. (by #link("https://zzzcode.ai")[zzzcode.ai])

*Резюме*

Код представляет собой реализацию нескольких классов, включая `Gamer`, `Book`, `Magazine`, `Item`, `Triangle`, `Line`, `Point`, и прогрессии. Основная логика кода заключается в моделировании игровых сессий и библиотечных предметов. Однако, код требует улучшений в области стиля, структуры и обработки ошибок.

*Ошибка*

В классе `Gamer` отсутствует проверка на `null` для параметра `name` в конструкторе. Это может привести к исключению, если передать `null`. Также метод `random()` в классе `IgralnayaKost` не определен в предоставленном коде, что может вызвать ошибки компиляции.


*Стиль кода*

Имена переменных и методов должны следовать соглашениям о наименовании C\#. Например, `Name` и `seans` следует переименовать в `name` и `session` соответственно. Рекомендуется использовать свойства вместо полей для обеспечения инкапсуляции.

*Структура кода*

Код разбит на несколько классов, что хорошо для организации. Однако, стоит рассмотреть возможность разделения на отдельные файлы для каждого класса, чтобы улучшить читаемость и поддержку.

*Читаемость*

Код в целом читаем, но использование комментариев и документации для методов и классов значительно улучшит понимание кода другими разработчиками.

*Производительность*

Код не содержит явных проблем с производительностью, однако использование статических методов и свойств может быть оптимизировано для уменьшения потребления памяти.

*Масштабируемость*

Код может быть расширен, но для этого потребуется более четкая архитектура. Например, использование интерфейсов для классов `Item`, `Book`, и `Magazine` может улучшить гибкость и масштабируемость.

*Безопасность*

Отсутствие проверки входных данных может привести к уязвимостям. Рекомендуется добавить валидацию для всех входных параметров, особенно в конструкторах.

*Обработка ошибок*

Код не содержит механизма обработки ошибок. Рекомендуется использовать конструкции `try-catch` для обработки возможных исключений, особенно в методах, которые могут вызывать ошибки, такие как `random()`.

*Заключение*

Код демонстрирует базовые принципы объектно-ориентированного программирования, но требует улучшений в области стиля, структуры и обработки ошибок. Рекомендуется провести рефакторинг для повышения читаемости и безопасности, а также добавить документацию для улучшения поддержки кода в будущем.


