351 lines
12 KiB
Typst
351 lines
12 KiB
Typst
#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)[Лабораторная работа №8]
|
||
#align(center)[Использование интерфейсов при реализации иерархии классов]
|
||
\
|
||
\
|
||
\ //#align(center)[Вариант 19]
|
||
\
|
||
\
|
||
\
|
||
\
|
||
\
|
||
\
|
||
\
|
||
#align(right)[Выполнил:]
|
||
#align(right)[Дощенников Никита Андреевич]
|
||
#align(right)[Группа: К3221]
|
||
#align(right)[Проверил:]
|
||
#align(right)[Иванов Сергей Евгеньевич]
|
||
\
|
||
\
|
||
#align(center)[Санкт-Петербург]
|
||
#align(center)[2025]
|
||
|
||
#pagebreak()
|
||
|
||
=== Цель работы:
|
||
|
||
Использовать интерфейсы при реализации иерархии классов как важного элемента объектно-ориентированного программирования и приобретение навыков реализации интерфейсов.
|
||
|
||
=== Упражнение 1. Создание и реализация интерфейса.
|
||
|
||
В этом упражнении я создал интерфейс, определяющий поведение классов, которые будут его реализовывать.
|
||
|
||
```cs
|
||
using System;
|
||
|
||
interface IPubs
|
||
{
|
||
void Subs();
|
||
bool IfSubs { get; set; }
|
||
}
|
||
```
|
||
|
||
```cs
|
||
using System;
|
||
|
||
class Magazine : Item, IPubs
|
||
{
|
||
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;
|
||
}
|
||
|
||
public bool IfSubs { get; set; }
|
||
|
||
public void Subs()
|
||
{
|
||
Console.WriteLine("Подписка на журнал \"{0}\": {1}.", title, IfSubs);
|
||
}
|
||
|
||
}
|
||
```
|
||
|
||
Тесты:
|
||
|
||
```cs
|
||
public static void Main(string[] args)
|
||
{
|
||
Magazine mag1 = new Magazine("О природе", 5, "Земля и мы", 2014, 1235, true);
|
||
mag1.TakeItem();
|
||
mag1.Show();
|
||
mag1.IfSubs = true;
|
||
mag1.Subs();
|
||
}
|
||
```
|
||
|
||
Пример:
|
||
|
||
#align(center)[#image("assets/1.png")]
|
||
|
||
=== Упражнение 2. Использование стандартных интерфейсов.
|
||
|
||
В этом упражнении я применил интерфейс `IComparable`, который задает метод сравнения объектов по принципу больше и меньше, что позволяет переопределить соответствующие операции в рамках класса, наследующего интерфейс `IComparable`.
|
||
|
||
```cs
|
||
using System;
|
||
|
||
abstract class Item : IComparable
|
||
{
|
||
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);
|
||
}
|
||
|
||
int IComparable.CompareTo(object obj)
|
||
{
|
||
Item it = (Item)obj;
|
||
if (this.invNumber == it.invNumber) return 0;
|
||
else if (this.invNumber > it.invNumber) return 1;
|
||
else return -1;
|
||
}
|
||
}
|
||
```
|
||
|
||
Тесты:
|
||
|
||
```cs
|
||
public static void Main(string[] args)
|
||
{
|
||
Item[] items = new Item[4];
|
||
items[0] = b1;
|
||
items[1] = b2;
|
||
items[2] = b3;
|
||
items[3] = mag1;
|
||
|
||
Array.Sort(items);
|
||
|
||
Console.WriteLine("\nСортировка по инвентарному номеру");
|
||
foreach (Item x in items)
|
||
{
|
||
x.Show();
|
||
}
|
||
}
|
||
```
|
||
|
||
Пример:
|
||
|
||
#align(center)[#image("assets/2.png")]
|
||
|
||
=== Упражнение 3. Реализация прогрессии с помощью интерфейса.
|
||
|
||
В этом упражнении я заменил абстрактный класс `Progression` на интерфейс `IProgression`, определяющий поведение классов `ArithmeticProgression` и `GeometricProgression`, описывающих арифметическую и геометрическую прогрессии.
|
||
|
||
```cs
|
||
using System;
|
||
|
||
interface IProgression
|
||
{
|
||
int GetElement(int k);
|
||
int Sum(int n);
|
||
}
|
||
```
|
||
|
||
```cs
|
||
using System;
|
||
|
||
class ArithmeticProgression : IProgression
|
||
{
|
||
private int a0;
|
||
private int b;
|
||
|
||
public ArithmeticProgression(int a0, int b)
|
||
{
|
||
this.a0 = a0;
|
||
this.b = b;
|
||
}
|
||
|
||
public int GetElement(int k)
|
||
{
|
||
return a0 + (k - 1) * b;
|
||
}
|
||
|
||
public int Sum(int n)
|
||
{
|
||
return (2 * a0 + (n - 1) * b) * n / 2;
|
||
}
|
||
}
|
||
```
|
||
|
||
```cs
|
||
using System;
|
||
|
||
class GeometricProgression : IProgression
|
||
{
|
||
private int p0;
|
||
private int q;
|
||
|
||
public GeometricProgression(int p0, int q)
|
||
{
|
||
this.p0 = p0;
|
||
this.q = q;
|
||
}
|
||
|
||
public int GetElement(int k)
|
||
{
|
||
return p0 * (int)Math.Pow(q, k - 1);
|
||
}
|
||
|
||
public 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)
|
||
{
|
||
IProgression arith = new ArithmeticProgression(2, 3);
|
||
IProgression 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/3.png")]
|
||
|
||
=== Выводы.
|
||
|
||
В ходе проделанной лабораторной работы я использовал интерфейсы при реализации иерархии классов как важного элемента объектно-ориентированного программирования и приобретел навыки реализации интерфейсов.
|
||
|
||
=== Code review. (by #link("https://zzzcode.ai")[zzzcode.ai])
|
||
|
||
*Резюме*
|
||
|
||
Класс `Book` представляет собой реализацию книги с различными атрибутами, такими как автор, название, издатель и т.д. Он наследуется от абстрактного класса `Item`, который управляет состоянием доступности книги. Код в целом хорошо структурирован, но требует некоторых улучшений в области стиля и производительности.
|
||
|
||
*Ошибка*
|
||
|
||
В методе `Return()` класса `Book` переменная `taken` устанавливается в значение `returnSrok`, которое по умолчанию равно `false`. Это может привести к тому, что книга будет считаться возвращенной, даже если она не была возвращена. Следует добавить логику для проверки состояния возврата.
|
||
|
||
*Стиль кода*
|
||
|
||
Использование `String` вместо `string` не соответствует общепринятому стилю C\#. Рекомендуется использовать `string` (с маленькой буквы). Имена переменных и методов должны следовать соглашениям о наименовании. Например, `returnSrok` можно переименовать в `isReturned` для большей ясности.
|
||
|
||
*Структура кода*
|
||
|
||
Класс `Book` имеет хорошую структуру, однако: Конструкторы перегружены, что может усложнить создание объектов. Рекомендуется использовать один конструктор с параметрами по умолчанию. Метод `SetBook` можно заменить на использование свойств, что улучшит инкапсуляцию.
|
||
|
||
*Читаемость*
|
||
|
||
Код читаем, но можно улучшить: Добавить XML-комментарии к методам и классам для лучшего понимания их назначения. Разделить длинные строки на несколько строк для повышения читаемости.
|
||
|
||
*Производительность*
|
||
|
||
Статическая переменная `price` может быть изменена через метод `SetPrice`, что может привести к неожиданным изменениям. Рекомендуется сделать её свойством только для чтения или использовать паттерн Singleton для управления ценой.
|
||
|
||
*Масштабируемость*
|
||
|
||
Класс `Book` может быть расширен для поддержки дополнительных атрибутов, таких как жанр или ISBN. Однако, если количество атрибутов увеличится, стоит рассмотреть возможность использования паттерна проектирования, такого как `Builder`.
|
||
|
||
*Безопасность*
|
||
|
||
Необходимо добавить валидацию входных данных в конструкторах и методах, чтобы предотвратить создание объектов с некорректными значениями (например, отрицательное количество страниц или год).
|
||
|
||
*Обработка ошибок*
|
||
|
||
В текущем коде отсутствует обработка исключений. Рекомендуется добавить обработку ошибок, особенно в методах, которые могут вызывать исключения, таких как `PriceBook`.
|
||
|
||
*Заключение*
|
||
|
||
Класс `Book` и его реализация в целом являются хорошей основой для работы с книгами. Однако, для улучшения качества кода и его поддержки, необходимо внести изменения в стиль, структуру и обработку ошибок. Рекомендуется также рассмотреть возможность добавления тестов для проверки функциональности классов.
|
||
|
||
|