← Назад к вопросам

Приведи пример использования принципа interface segregation

2.0 Middle🔥 111 комментариев
#Архитектура Flutter#ООП и паттерны

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Пример использования принципа Interface Segregation (ISP) в Dart/Flutter

Interface Segregation Principle (ISP) из SOLID гласит: клиент не должен зависеть от интерфейсов, которые он не использует. Вместо одного большого интерфейса создавай несколько маленьких, специфичных.

Концепция ISP

// Интерфейс Segregation = разделение на узкие интерфейсы
// вместо одного толстого интерфейса

// ❌ Плохо: Один большой интерфейс
abstract class Animal {
  void eat();
  void sleep();
  void fly();        // Но не все животные летают!
  void swim();       // Но не все животные плавают!
  void bark();       // Но не все издают звуки!
}

class Dog implements Animal {
  @override
  void eat() => print('Dog eats');
  
  @override
  void sleep() => print('Dog sleeps');
  
  @override
  void fly() => throw UnimplementedError();  // Ненужный метод!
  
  @override
  void swim() => throw UnimplementedError();  # Может не нужен
  
  @override
  void bark() => print('Woof!');
}

// ✅ Хорошо: Маленькие, специфичные интерфейсы
abstract class Eater {
  void eat();
}

abstract class Sleeper {
  void sleep();
}

abstract class Flyer {
  void fly();
}

abstract class Swimmer {
  void swim();
}

abstract class VocalAnimal {
  void makeSound();
}

class Dog implements Eater, Sleeper, VocalAnimal {
  @override
  void eat() => print('Dog eats');
  
  @override
  void sleep() => print('Dog sleeps');
  
  @override
  void makeSound() => print('Woof!');
  
  // Никаких ненужных методов!
}

class Duck implements Eater, Sleeper, Flyer, Swimmer, VocalAnimal {
  @override
  void eat() => print('Duck eats');
  
  @override
  void sleep() => print('Duck sleeps');
  
  @override
  void fly() => print('Duck flies');
  
  @override
  void swim() => print('Duck swims');
  
  @override
  void makeSound() => print('Quack!');
}

Практический пример: User Management System

❌ Плохо: Один большой интерфейс

// Слишком много методов!
abstract class User {
  String getName();
  String getEmail();
  void setEmail(String email);
  void setPassword(String password);
  bool canDelete();
  bool canEdit();
  bool canManageUsers();
  bool canViewAnalytics();
  bool canPublishContent();
  void publishContent();
  void viewAnalytics();
  void manageUsers();
  List<Role> getRoles();
  List<Permission> getPermissions();
  Future<void> sendNotification(String message);
  Future<void> sendEmail(String subject, String body);
  void logActivity(String action);
  void updateLastLogin();
  Map<String, dynamic> toJson();
  String toXml();
  String toCsv();
}

// Администратор должен реализовать всё
class AdminUser implements User {
  // 20+ методов!
  // Много ненужных методов
}

// Гость должен реализовать всё
class GuestUser implements User {
  // 20+ методов, но большинство вернёт false или выбросит ошибку
  // Очень неудобно
}

✅ Хорошо: Разделены на маленькие интерфейсы

// Основная информация о пользователе
abstract class UserProfile {
  String getName();
  String getEmail();
  void setEmail(String email);
}

// Безопасность
abstract class UserAuthentication {
  void setPassword(String password);
  bool verifyPassword(String password);
}

// Права доступа
abstract class UserAuthorization {
  bool canDelete();
  bool canEdit();
  List<Permission> getPermissions();
}

// Публикация контента
abstract class ContentPublisher {
  void publishContent(String content);
  void unpublishContent(String contentId);
}

// Просмотр аналитики
abstract class AnalyticsViewer {
  Map<String, dynamic> getAnalytics();
  void viewReport(String reportId);
}

// Управление пользователями
abstract class UserManager {
  void createUser(User user);
  void deleteUser(int userId);
  void assignRole(int userId, Role role);
}

// Уведомления
abstract class Notifiable {
  Future<void> sendNotification(String message);
  Future<void> sendEmail(String subject, String body);
}

// Логирование
abstract class Auditable {
  void logActivity(String action);
  void updateLastLogin();
}

// Сериализация
abstract class Serializable {
  Map<String, dynamic> toJson();
  String toXml();
  String toCsv();
}

// Теперь каждый пользователь реализует только нужные интерфейсы
class AdminUser implements 
  UserProfile,
  UserAuthentication,
  UserAuthorization,
  ContentPublisher,
  AnalyticsViewer,
  UserManager,
  Notifiable,
  Auditable,
  Serializable {
  
  @override
  String getName() => 'Admin';
  
  @override
  String getEmail() => 'admin@example.com';
  
  @override
  void setEmail(String email) {}
  
  @override
  void setPassword(String password) {}
  
  @override
  bool verifyPassword(String password) => true;
  
  @override
  bool canDelete() => true;  // Может удалять
  
  @override
  bool canEdit() => true;    # Может редактировать
  
  @override
  List<Permission> getPermissions() => [Permission.all()];
  
  // Остальные методы...
}

class ContentCreator implements 
  UserProfile,
  UserAuthentication,
  UserAuthorization,
  ContentPublisher,
  Notifiable,
  Auditable {
  
  // Только то, что нужно для создателя контента
  // Нет методов управления пользователями
  // Нет методов просмотра аналитики
  
  @override
  void publishContent(String content) => print('Publishing...');
  
  @override
  bool canDelete() => false;  // Не может удалять
  
  @override
  bool canEdit() => true;     // Может редактировать
  
  // Другие методы...
}

class GuestUser implements UserProfile, Notifiable {
  // Только профиль и уведомления
  // Никаких прав и управления
  
  @override
  String getName() => 'Guest';
  
  @override
  String getEmail() => 'guest@example.com';
  
  @override
  void setEmail(String email) {
    throw Exception('Guest cannot change email');
  }
  
  @override
  Future<void> sendNotification(String message) => print('Notification: $message');
}

Пример 2: Payment System

❌ Плохо: Толстый интерфейс платежа

abstract class PaymentGateway {
  Future<PaymentResult> pay(double amount);
  Future<RefundResult> refund(String transactionId);
  Future<List<Transaction>> getTransactionHistory();
  Future<void> validateCard(String cardNumber);
  Future<void> setupRecurringPayment(double amount);
  Future<void> cancelRecurringPayment();
  bool supportsSplit();
  Future<void> splitPayment(List<int> amounts);
  Future<Map> getExchangeRate(String currency);
  bool supportsInstallments();
  Future<void> payWithInstallments(int months);
}

// Простой платёж может не поддерживать всё
class StripeGateway implements PaymentGateway {
  // Много методов для реализации
  // Некоторые не имеют смысла
}

✅ Хорошо: Маленькие, специфичные интерфейсы

// Базовый платёж
abstract class PaymentProcessor {
  Future<PaymentResult> processPayment(PaymentData data);
}

// Возврат денег
abstract class Refundable {
  Future<RefundResult> refund(String transactionId);
}

// История платежей
abstract class TransactionHistoryProvider {
  Future<List<Transaction>> getTransactionHistory();
}

// Валидация карты
abstract class CardValidator {
  Future<void> validateCard(String cardNumber);
}

// Подписки/Recurring платежи
abstract class RecurringPaymentSupport {
  Future<void> setupRecurringPayment(double amount);
  Future<void> cancelRecurringPayment();
}

// Разделение платежа
abstract class SplitPaymentSupport {
  Future<void> splitPayment(List<int> amounts);
}

// Обмен валюты
abstract class CurrencyExchange {
  Future<Map> getExchangeRate(String currency);
}

// Рассрочка
abstract class InstallmentSupport {
  Future<void> payWithInstallments(int months);
}

// Stripe поддерживает основное
class StripeGateway implements 
  PaymentProcessor,
  Refundable,
  TransactionHistoryProvider,
  CardValidator,
  RecurringPaymentSupport {
  
  @override
  Future<PaymentResult> processPayment(PaymentData data) async {
    // Реализация
    return PaymentResult.success('stripe_tx_123');
  }
  
  @override
  Future<RefundResult> refund(String transactionId) async {
    // Реализация
    return RefundResult.success();
  }
  
  // Остальные методы...
}

// Google Pay простой платёж
class GooglePayGateway implements PaymentProcessor, CardValidator {
  @override
  Future<PaymentResult> processPayment(PaymentData data) async {
    return PaymentResult.success('google_pay_123');
  }
  
  @override
  Future<void> validateCard(String cardNumber) async {}
  
  // Только то, что нужно Google Pay
}

// PayPal поддерживает всё
class PayPalGateway implements 
  PaymentProcessor,
  Refundable,
  TransactionHistoryProvider,
  RecurringPaymentSupport,
  InstallmentSupport,
  SplitPaymentSupport,
  CurrencyExchange {
  
  // Полная реализация
}

// Использование
class CheckoutService {
  Future<void> processPayment(PaymentProcessor gateway) async {
    // Работает с любым gateway который реализует PaymentProcessor
    final result = await gateway.processPayment(paymentData);
    print('Payment: $result');
  }
  
  Future<void> refundPayment(Refundable gateway, String txId) async {
    // Работает только с Refundable gateway
    final result = await gateway.refund(txId);
    print('Refund: $result');
  }
  
  Future<void> setupSubscription(RecurringPaymentSupport gateway) async {
    // Работает только с gateway поддерживающей recurring платежи
    await gateway.setupRecurringPayment(99.99);
  }
}

Пример 3: Database Repository

❌ Плохо: Большой интерфейс

abstract class Repository<T> {
  Future<List<T>> findAll();
  Future<T?> findById(int id);
  Future<void> create(T entity);
  Future<void> update(T entity);
  Future<void> delete(int id);
  Future<void> deleteAll();
  Future<int> count();
  Future<List<T>> findByQuery(String query);
  Future<void> batchCreate(List<T> entities);
  Future<void> batchDelete(List<int> ids);
  Future<void> softDelete(int id);
  Future<void> restore(int id);
  Future<List<T>> findDeleted();
  Stream<List<T>> watch();
}

✅ Хорошо: Разделены на маленькие

// Чтение
abstract class ReadOnlyRepository<T> {
  Future<List<T>> findAll();
  Future<T?> findById(int id);
}

// Создание
abstract class CreateRepository<T> {
  Future<void> create(T entity);
  Future<void> batchCreate(List<T> entities);
}

// Обновление
abstract class UpdateRepository<T> {
  Future<void> update(T entity);
}

// Удаление
abstract class DeleteRepository<T> {
  Future<void> delete(int id);
  Future<void> deleteAll();
  Future<void> batchDelete(List<int> ids);
}

// Мягкое удаление
abstract class SoftDeleteRepository<T> {
  Future<void> softDelete(int id);
  Future<void> restore(int id);
  Future<List<T>> findDeleted();
}

// Поиск
abstract class SearchableRepository<T> {
  Future<List<T>> findByQuery(String query);
}

// Статистика
abstract class CountableRepository<T> {
  Future<int> count();
}

// Мониторинг
abstract class WatchableRepository<T> {
  Stream<List<T>> watch();
}

// Полный репозиторий
class UserRepository implements 
  ReadOnlyRepository<User>,
  CreateRepository<User>,
  UpdateRepository<User>,
  DeleteRepository<User>,
  SoftDeleteRepository<User>,
  SearchableRepository<User>,
  CountableRepository<User>,
  WatchableRepository<User> {
  
  // Полная реализация
}

// Простой читаемый репозиторий
class ConfigRepository implements ReadOnlyRepository<Config> {
  @override
  Future<List<Config>> findAll() async => [];
  
  @override
  Future<Config?> findById(int id) async => null;
  
  // Больше ничего не нужно
}

Преимущества ISP

// ✅ Клиент зависит только от нужных методов
class PaymentService {
  Future<void> processPayment(PaymentProcessor gateway) async {
    // Знаем только о processPayment
    // Не нужно знать о refund, installments и т.д.
    await gateway.processPayment(data);
  }
}

// ✅ Легко добавлять новые функции
class RefundService {
  Future<void> refundPayment(Refundable gateway, String txId) async {
    // Работает только с Refundable
    // Просто и понятно
    await gateway.refund(txId);
  }
}

// ✅ Легко тестировать
class MockPaymentGateway implements PaymentProcessor {
  @override
  Future<PaymentResult> processPayment(PaymentData data) async {
    return PaymentResult.success('mock_tx');
  }
  
  // Остальные методы не нужны
}

Резюме ISP

Interface Segregation Principle:

  1. Разделяй большие интерфейсы на маленькие

    • Вместо 20 методов → несколько интерфейсов
  2. Каждый интерфейс = одна ответственность

    • PaymentProcessor только для платежей
    • Refundable только для возвратов
  3. Клиент реализует только нужные интерфейсы

    • SimplePayment не реализует Refundable
    • GuestUser не реализует UserManager
  4. Меньше зависимостей

    • PaymentService зависит только от PaymentProcessor
    • Не нужно знать о других методах

Результат:

  • ✅ Чище код
  • ✅ Проще тестировать
  • ✅ Лучше архитектура
  • ✅ Меньше связанности
  • ✅ Легче добавлять функции
Приведи пример использования принципа interface segregation | PrepBro