#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()`. *Заключение* Код демонстрирует базовые принципы объектно-ориентированного программирования, но требует улучшений в области стиля, структуры и обработки ошибок. Рекомендуется провести рефакторинг для повышения читаемости и безопасности, а также добавить документацию для улучшения поддержки кода в будущем.