Files
oop/labs/lab7_done/report.typ
2025-09-30 14:26:54 +03:00

601 lines
17 KiB
Typst
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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