Uploaded by anonimov9990

Практична робота 14

advertisement
Практична робота 14. Інтерфейсні класи
Мета роботи - отримання практичних навичок створення інтерфейсних
класів.
Інтерфейс (також називають інтерфейсний клас) – абстрактний клас, що
містить лише абстрактні методи.
Поруч із абстрактними класами, інтерфейси встановлюють взаємообов’язки
між елементами програмної системи.
Тоді, можна зробити висновок, що інтерфейси не містять даних (тобто полів,
статичних у тому ж числі), а всі їхні методи необхідно реалізувати у нащадках.
Про клас-нащадок, кажуть, що він реалізує інтерфейс. Інтерфейси
дозволяють використовувати множинне наслідування і в той же час вирішити
проблему ромбовидного наслідування – оскільки даних немає, а всі методи
абстрактні і підлягають заміщенню, то відпадає проблема неоднозначності при
виборі методу або зверненні до полів даних.
Питання коли використовувати інтерфейси, а коли абстрактні класи не
однозначне, проте існує кілька характеристик, які однозначно кажуть, яку сутність
використовувати.
Абстрактний клас використовують коли існує ряд характеристик, що
об’єднують групу у єдину ієрархію. Інтерфейс використовують коли потрібно
відобразити лише зовнішню схожість поведінки об’єктів класів, для яких навіть не
можна (або складно) побудувати ієрархію, які власне не знаходяться у якихось
родинних зв’язках. Наприклад, метод listen() може бути визначений (по різному)
для найрізноманітніших класів – Human, Animal, MobilePhone, Microphone тощо.
Серед них не можливо виділити предка, оскільки їх всіх об’єднує лише
властивість, що вони можуть слухати. Тоді можна оголосити інтефейс Listener
(слухач), що буде мати абстрактний метод listen(), а кожен з класів перехованих
вище буде реалізовувати цей інтерфейс по своєму. Отже, фактично основне
призначення інтерфейсних класів – це гарантувати додаткові конкретно визначені
можливості для екземплярів різнотипових класів!
Реалізація інтефейсів у Python здійснюється за допомогою модуля
zope.interfaces який потрібно додатково встановлювати. Проте можна
користуватися підходом абстрактний класів.
Приклад:
Діагностувати можна різні об’єкти – автомобілі, здоров’я людей чи тварин,
техніку. Отже, можна описати інтерфейс Diagnostics, який буде містити
(абстрактний) метод diagnose() – діагностування стану об’єкту. Опишемо базові
класи Car та Human. На основі вищенаведених базових класів опишемо конкретні
класи DiagnosticsCar та DiagnosticsHuman відповідно, кожен з яких, крім цього,
буде реалізовувати інтерфейс Diagnostics. Отже, будь-який екземпляр класів
DiagnosticsCar та DiagnosticsHuman можна буде діагностувати (причому ця
діагностика буде залежати від того, до якого класу належить об’єкт).
class Diagnostics(metaclass=ABCMeta):
@abstractmethod
def diagnose(self):
pass
class Car:
def __init__(self, resource=100000):
self._resource = resource
self._current_mileage = 0
def driving(self):
self._current_mileage += 15000
class Human:
def __init__(self):
self._health = 100
def eat(self, food):
if food == "Шкідлива їжа":
self._health -= 20
elif food == "здорова їжа":
self._health += 20
self._health = self._health if self._health > 0 else 0
self._health = self._health if self._health < 100 else 1000
class DiagnosticsCar(Car, Diagnostics):
def diagnose(self):
if self._current_mileage >= self._resource:
return "Ваш автомобіль потребує капітального ремонту"
rest = self._resource - self._current_mileage
rest /= self._resource
rest *= 100
return "Залишок {}% ресурсу".format(rest)
class DiagnosticsHuman(Human, Diagnostics):
def diagnose(self):
if self._health <= 0:
return "Нездорова їжа вбиває вас"
elif self._health == 1100:
return "Здоров'я у вас чудове"
else:
return "Будь ласка, відвідайте лікаря "
c = DiagnosticsCar()
h = DiagnosticsHuman()
for i in range(10):
c.driving()
h.eat(" ")
print(c.diagnose())
print(h.diagnose())
Ваш автомобіль потребує капітального ремонту
Будь ласка, відвідайте лікаря
Класи домішки
Домішки (англ. mixin) – це класи, які додають до іншого класу визначену
функціональність через механізм множинного наслідування.
Концепція домішків будується на ідеї чіткого розмежування властивостей і
методів для сутностей – тобто даних і алгоритмів. Фактично домішки є різновидом
множинного наслідуванні і синтаксично нічим від нього не відрізняються. Проте
потрібно пам’ятати деяку їхню специфіку: домішки не призначені для породження
самостійних екземплярів класів – вони слугують для того, щоб додати визначену
функціональність будь-якому іншому класу.
Домішки є близькою концепцією до інтерфейсів, проте спід пам’ятати, що
інтерфейс надає лише специфікацію поведінки, без її реалізації, у той час, як
домішки містять і повну реалізацію. Крім того, як ми пам’ятаємо, інтерфейси
використовуються для неспоріднених класів, серед яких інколи не можливо
встановити ієрархію.
Відповідно, домішки застосовуються для того, щоб розширити функціонал
подібних класів, що (навіть якщо не можна побудувати ієрархію) мають багато
спільних рис.
Приклад:
class Animal(metaclass = ABCMeta):
def __init__(self, name, legs, color):
self._name = name
self._legs = legs
self._color = color
Опишемо клас домішок Additive, що буде містити метод, що виводить повну
інформацію про конкретну тварину.
class Additive:
def log(self):
print("========= Клас:", self.__class__.__name__)
print("Кличка тварини:", self._name)
print("Кількість лап: ", self._legs)
print("Окрас: ", self._color)
Очевидно, що сам по собі цей клас не має сенсу, оскільки його метод log()
намагається використати поля self._name, self._legs та self._fleas яких у ньому
немає.
Застосуємо цей домішок для класів Fox та Leopard.
class Fox(Animal):
def lives(self):
print("fox", self._name, "lives in the woods")
class Leopard(Animal):
def lives(self):
print("leopard", self._name, "lives in the mountains")
Для цього опишемо класи AdditiveFox та AdditiveLeopard, що будуть містити
у якості базових класів клас-домішок і відповідно клас Fox та Leopard.
class AdditiveFox(Additive, Fox):
pass
class AdditiveLeopard(Additive, Leopard):
pass
c = AdditiveFox("Alissa", 4, "Рудий")
d = AdditiveLeopard("Murchik", 4, "П'ятнистий")
c.log()
d.log()
Кличка тварини: Alissa
Кількість лап: 4
Окрас: Рудий
========= Клас: AdditiveLeopard
Кличка тварини: Murchik
Кількість лап: 4
Окрас: П'ятнистий.
Самостійне завдання:
Логістична компанія отримала завдання на доставку двадцятифутових
контейнерів у кількості 400 штук із порту А, розташованого на річці, на залізничну
станцію D.
Є три способи доставки з А в D:
1. По річці на вантажному судні від А до порту, потім автомобільним
транспортом до від С до D.
2. Автомобільним транспортом від А до D.
3. Автомобільним транспортом від А до залізничної станції, потім по
залізниці від В до D.
Логістична компанія для виконання завдання може замовити судна, що
дислоковані у пункті А, залізничні склади, що дислоковані у пункті В, а також
автомобільний транспорт, який дислокований у пункті D. Після виконання
замовлення всі транспортні засоби мають бути доставлені до місць дислокації за
рахунок логістичної компанії.
Час завантаження або розвантаження одного контейнера для будь-якого
транспортного засобу становить 15 хв.
На кожному завантаженні чи розвантаженні працює по одному вантажнорозвантажувальному пристрої.
Замовник ставить завдання доставити вантаж максимально швидким
способом, але за умови, що збільшення ціни за прискорення доставки не повинно
бути більш ніж на 15% вище за ціну найповільнішого варіанту.
Необхідно визначити оптимальний варіант доставки партії контейнерів за
умови, що пересувні транспортні засоби працюють безперервно протягом доби і
вирушають у дорогу відразу після закінчення навантаження або розвантаження.
Таблиця 1. Параметри транспортної системи
Вид транспорту i Експлуатаційна
Вантажопідйомність
швидкість рухуViЭ, транспортного
км./час
контейнерів
Gi Максимально
Вартість
засобу, можливе замовлення замовлення
Ni
транспортних транспортного
засобів, штук
засобу
грн./км.
1. Річковий
16
500
1
360
2. Автомобільний 35
2
40
12
3. Залізничний
200
1
440
20
Таблиця 2. Відстані ділянок
Вид транспорту
Ділянка транспортної мережі
Довжина ділянки
Річковий
АС
84
Автомобільний
АD
56
АВ
60
СD
24
ВD
80
Залізничний
Моделювання варіантів доставки вантажу
Si,
Час перевезення одним транспортним засобом складається з витрат часу
попри всі транспортно-логістичні операції, необхідних здійснення перевезення цим
транспортним засобом.
Слід брати до уваги, що операції, що здійснюються різними транспортними
засобами, накладаються одна на одну в часі. Загальні витрати часу становлять
інтервал між моментами початку та закінчення замовлення.
Розрахунок витрат часу при пересуванні здійснюється за формулою:
T = (Tнавант + Tперевоз + Tрозван + Tперегін),
де Tнавантаження - час навантаження;
Tперевезення - час перевезення;
Tрозвантаження - час розвантаження;
Tперегін - неодружена їздка (їздка без вантажу).
Загальний час навантаження або вивантаження для одного транспортного
засобу дорівнює добутку часу навантаження одного контейнера (Тконт) на їх
кількість (Кконт) та складе:
Tпогруз=Tразгруз=Тконт*Кконт
Загальний час навантаження чи вивантаження всього вантажу становитиме:
Tпогруз=Tразгруз=( Тконт*Кконт)*Ктс,
где Ктс – кількість транспортних засобів
Час
на
транспортного
перевезення
вантажу
засобу
визначається
та
дорівнює
часу
розподілом
зворотного
довжини
перегону
ділянки
на
експлуатаційну швидкість:
Tперевоз = Tперегон= L/Vэ
Час для перевезення всього вантажу буде потрібний як сума часу на
навантаження (Tнавантаження), транспортування (Tперевезення) помножена на
кількість їздок (Кїзд):
T = (Tперевоз+ Tпогруз)*Кезд
Вибір оптимального варіанта доставки вантажу
Для вибору оптимального варіанта розраховуються витрати на оренду
транспортних засобів у кожному сценарії, виходячи з сумарного пробігу,
здійсненого
всіма
транспортними
засобами
цього
сценарію.
При
цьому
враховується як холостий пробіг (Lперегон) при перегоні транспортного засобу, так і
пробіг під навантаженням (Lперевезення).
Сумарний пробіг усіх транспортних засобів розраховується за такими
формулами:
1.
LАС = (LперевозАС + LперегонСА)
2.
LСВ = (LперегонВС +LперевозСВ) * Ктс * Кезд
Download