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

Что такое интерфейс в ООП?

1.0 Junior🔥 181 комментариев
#ООП и паттерны

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

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

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

Что такое интерфейс в ООП?

Интерфейс — это контракт (соглашение) между классом и внешним миром, который определяет, какие методы и свойства должен реализовать класс. Интерфейс не содержит реализацию, только определение методов.

Основные концепции

Интерфейс — это абстрактное определение возможностей. Он говорит: "Класс, который реализует этот интерфейс, ДОЛЖЕНч иметь эти методы".

Интерфейс - КОНТРАКТ

Датчик интерфейса говорит:
┌─────────────────────┐
│    Sensor           │
├─────────────────────┤
│ read() -> int       │
│ isActive() -> bool  │
└─────────────────────┘
     ↓         ↓         ↓
┌─────────┐ ┌──────────┐ ┌──────────────┐
│Temperature│ │Humidity  │ │Pressure      │
├─────────┤ ├──────────┤ ├──────────────┤
│ read()    │ │ read()   │ │ read()       │
│isActive() │ │isActive()│ │isActive()    │
└─────────┘ └──────────┘ └──────────────┘

Интерфейс в Dart

В Dart каждый класс автоматически является интерфейсом. Реализуется через implements:

abstract class Animal {
  void eat();
  void sleep();
  String makeSound();
}

class Dog implements Animal {
  @override
  void eat() {
    print('Собака ест');
  }

  @override
  void sleep() {
    print('Собака спит');
  }

  @override
  String makeSound() {
    return 'Гав!';
  }
}

class Cat implements Animal {
  @override
  void eat() {
    print('Кошка ест');
  }

  @override
  void sleep() {
    print('Кошка спит');
  }

  @override
  String makeSound() {
    return 'Мяу!';
  }
}

Интерфейс vs Абстрактный класс

Интерфейс (implements):

  • Только сигнатуры методов
  • Можно реализовать несколько интерфейсов
  • Множественное наследование
class Penguin implements Animal, Swimmer {
  // Реализует ОБА интерфейса
}

Абстрактный класс (extends):

  • Может иметь реализованные методы
  • Только один абстрактный класс
  • Одиночное наследование
abstract class Bird {
  void fly(); // Абстрактный
  void eat() { // Реализованный
    print('Ест зерно');
  }
}

Множественная реализация интерфейсов

abstract class Drawable {
  void draw();
}

abstract class Resizable {
  void resize(double scale);
}

abstract class Movable {
  void move(double x, double y);
}

class Rectangle implements Drawable, Resizable, Movable {
  double width = 100;
  double height = 50;
  double x = 0;
  double y = 0;

  @override
  void draw() {
    print('Рисую прямоугольник $width x $height');
  }

  @override
  void resize(double scale) {
    width *= scale;
    height *= scale;
  }

  @override
  void move(double x, double y) {
    this.x = x;
    this.y = y;
  }
}

Практические примеры в Flutter

Пример 1: Интерфейс для API сервиса

abstract class ApiClient {
  Future<T> get<T>(String url);
  Future<T> post<T>(String url, dynamic data);
  Future<T> put<T>(String url, dynamic data);
  Future<void> delete(String url);
}

class DioApiClient implements ApiClient {
  final Dio _dio;

  DioApiClient(this._dio);

  @override
  Future<T> get<T>(String url) async {
    final response = await _dio.get(url);
    return response.data as T;
  }

  @override
  Future<T> post<T>(String url, dynamic data) async {
    final response = await _dio.post(url, data: data);
    return response.data as T;
  }

  @override
  Future<T> put<T>(String url, dynamic data) async {
    final response = await _dio.put(url, data: data);
    return response.data as T;
  }

  @override
  Future<void> delete(String url) async {
    await _dio.delete(url);
  }
}

class MockApiClient implements ApiClient {
  @override
  Future<T> get<T>(String url) async {
    return {} as T; // Mock данные
  }

  @override
  Future<T> post<T>(String url, dynamic data) async {
    return {} as T;
  }

  @override
  Future<T> put<T>(String url, dynamic data) async {
    return {} as T;
  }

  @override
  Future<void> delete(String url) async {}
}

Пример 2: Интерфейс для хранилища

abstract class UserRepository {
  Future<User?> getUserById(String id);
  Future<void> saveUser(User user);
  Future<void> deleteUser(String id);
  Future<List<User>> getAllUsers();
}

class LocalUserRepository implements UserRepository {
  final SharedPreferences _prefs;

  LocalUserRepository(this._prefs);

  @override
  Future<User?> getUserById(String id) async {
    final json = _prefs.getString('user_$id');
    if (json == null) return null;
    return User.fromJson(jsonDecode(json));
  }

  @override
  Future<void> saveUser(User user) async {
    await _prefs.setString('user_${user.id}', jsonEncode(user.toJson()));
  }

  @override
  Future<void> deleteUser(String id) async {
    await _prefs.remove('user_$id');
  }

  @override
  Future<List<User>> getAllUsers() async {
    final keys = _prefs.getKeys();
    return [
      for (final key in keys)
        if (key.startsWith('user_'))
          User.fromJson(jsonDecode(_prefs.getString(key)!))
    ];
  }
}

class FirebaseUserRepository implements UserRepository {
  final FirebaseFirestore _firestore;

  FirebaseUserRepository(this._firestore);

  @override
  Future<User?> getUserById(String id) async {
    final doc = await _firestore.collection('users').doc(id).get();
    return doc.exists ? User.fromJson(doc.data()!) : null;
  }

  @override
  Future<void> saveUser(User user) async {
    await _firestore.collection('users').doc(user.id).set(user.toJson());
  }

  @override
  Future<void> deleteUser(String id) async {
    await _firestore.collection('users').doc(id).delete();
  }

  @override
  Future<List<User>> getAllUsers() async {
    final snapshot = await _firestore.collection('users').get();
    return [for (final doc in snapshot.docs) User.fromJson(doc.data())];
  }
}

Преимущества использования интерфейсов

  1. Абстракция: Скрываем детали реализации
ApiClient client = DioApiClient(dio);
// Можем легко изменить на:
ApiClient client = MockApiClient();
// Код который использует client не меняется!
  1. Тестируемость: Легко создавать mock объекты
class UserServiceTest {
  late MockApiClient mockClient;

  setUp(() {
    mockClient = MockApiClient();
  })

  test('should fetch user', () async {
    final service = UserService(mockClient);
    final user = await service.getUser('1');
    expect(user, isNotNull);
  });
}
  1. Гибкость: Легко менять реализацию без изменения кода
// Было:
class MyApp extends StatelessWidget {
  final apiClient = DioApiClient();
  // ...
}

// Стало:
class MyApp extends StatelessWidget {
  final apiClient = RetrofitApiClient(); // другая реализация
  // Код не изменился!
}
  1. Контракт: Гарантирует наличие всех необходимых методов

SOLID принцип: Dependency Inversion (DI)

Интерфейсы — основа DI:

class UserBloc {
  final UserRepository userRepository; // Интерфейс, не конкретная реализация
  final UserValidator validator;

  UserBloc(this.userRepository, this.validator);

  Future<void> registerUser(String email, String password) async {
    if (!validator.isValidEmail(email)) {
      throw InvalidEmailException();
    }
    await userRepository.saveUser(User(email: email, password: password));
  }
}

// Использование:
final repo = LocalUserRepository(prefs);
final bloc = UserBloc(repo, UserValidator());
// Или:
final repo = FirebaseUserRepository(firestore);
final bloc = UserBloc(repo, UserValidator());
// UserBloc не знает о деталях реализации!

Вывод

Интерфейсы — это фундамент объектно-ориентированного программирования. Они:

  • Определяют контракт
  • Облегчают тестирование
  • Снижают связанность кода
  • Позволяют легко менять реализацию
  • Соответствуют SOLID принципам

Используйте интерфейсы для всех публичных API, сервисов и репозиториев в Flutter приложениях.