4. Interface segregation principle
Принцип разделения интерфейса
СервисСайт рендериг приложение с клиентом и сервером
const client = () => { }
const server = () => { }
\n\n
СервисСайт рендериг приложение с клиентом и сервером
const client = () => { }
const server = () => { }
программные сущности не должны зависеть от методов, которые они не используют
разбивать толстые интерфейсы (программные сущности)
Положительность в принципе
класс база данных и есть классические операции
class Database {
connect(){} подключение
read(){} чтение каких-то данных
write(){} запись каких-то данных
joinTables(){} добавляем метод по объединению таблиц
}
класс реляционная база данных MySQLDataBase в которой все данные хранятся в форме связанных таблиц (уместен joinTables)
расширяет поведение базового класса Database
class MySQLDataBase extends Database{
connect(){}
read(){}
write(){}
joinTables(){}
}
при работе с дочерними классами мы должны быть уверены что ничего не сломается.
у нас есть какая-то стартовая точка в приложении
там мы конфигурируем базу данных и подключаемся к ней
и хотим выполнить какие-то операции.
При замене реляционной базы на не реляционную
например на МонгоБазу нарушается принцип Барбары Лисков
класс не реляционная база данных MongoDB и там данных хранятся в форме коллекции и документов
там таблиц нет и объединять таблицы мы не можем
class MongoDatabase extends Database {
connect(){}
read(){}
write(){}
переопределяем метод и выбрасываем ошибку
joinTables(){error}
}
при правильном проектировании было уместнее сделать сделать следующие.
Мы создаём ещё один класс, который наследует от базового. Из него мы удаляем метод joinTables
В таком случае, у нас в базовом классе определены операции, которые доступны только для всех баз данных (подключение, чтение, запись баз данных)
class Database {
connect(){} подключение
read(){} чтение каких-то данных
write(){} запись каких-то данных
joinTables(){}
}
специфичные методы для конкретного типа базы данных мы вынесли в отдельные классы
class SQLDataBase extends Database{
connect(){}
read(){}
write(){}
joinTables(){}
}
class NOSQLDatabase extends Database {
connect(){}
read(){}
write(){}
createIndex(){}
}
class MySQLDataBase extends SQLDatabase{
connect(){}
read(){}
write(){}
joinTables(){}
}
class MongoDatabase extends NOSQLDatabase {
connect(){}
read(){}
write(){}
createIndex(){}
mergerDocuments(){}
}
При запуске приложения мы на входе ожидаем какую-то базу данных. Какую базу данных мы бы не передали, у всех из них должен быть метод connect с предсказуемым поведением, который не замещает, а дополняет поведение базового класса
function startApp(database: Database){
database.connect();
}
startApp(new MongoDatabase);
startApp(new MySQLDatabase);
функции, сущности которые используют родительский тип
должны работать точно так же и с дочерними классами
наследуемый класс должен дополнять, а не замещать поведение базового класса
класс оружие Weapon
у него три поля type, damage, range (тип, урон, дистанция)
class Weapon {
type: string;
damage: number; // 0 - 100;
range: number; // 0 - 100;
contructor(type: string, damage: number, range: number) {
this.type = type;
this.damage = damage;
this.range = range;
}
}
класс персонаж Character
который может это оружие Weapon принимать через метод
class Character {
name: string;
weapon: Weapon;
contructor(name: string, weapon: Weapon) {
this.name = name;
this.weapon= weapon;
}
принимает оружие
changeWeapon(newWeapon:Weapon) {
this.weapon = newWeapon;
}
}