Menu
Coddy logo textTech

Фабричные конструкторы

Часть раздела Объектно-ориентированное программирование путешествия по Dart на Coddy. Урок 14 из 110.

factory constructor — это специальный конструктор, который не всегда создаёт новый экземпляр. В отличие от обычных конструкторов, factory constructor может вернуть существующий экземпляр, подтип или даже null (если допускается значение null). Вы объявляете его с помощью ключевого слова factory.

class Logger {
  static final Logger _instance = Logger._internal();
  
  // Приватный именованный конструктор
  Logger._internal();
  
  // Фабричный конструктор
  factory Logger() {
    return _instance;
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

В этом примере factory constructor всегда возвращает один и тот же instance. Независимо от того, сколько раз вы выполняете Logger(), вы получаете идентичный объект. Этот шаблон часто используется для реализации синглтонов.

Фабричные конструкторы отличаются от обычных конструкторов в одном ключевом отношении: у них нет доступа к this, поскольку они могут вообще не создавать новый экземпляр. Вместо этого они должны явно возвращать объект:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

Фабричные конструкторы полезны, когда вам нужен контроль над созданием instance, например для возврата кэшированных объектов, реализации пулов объектов или определения того, какой подтип создать на основе входных параметров.

challenge icon

Задание

Легко

Давайте создадим систему уведомлений, которая использует factory constructors для создания разных типов уведомлений на основе простой строковой входной величины.

Вы создадите два файла, чтобы организовать код:

  • notification.dart: Определите класс Notification, который служит базовым для всех типов уведомлений. Ваш class должен содержать:
    • поле String message
    • private named constructor Notification._internal, который инициализирует message
    • factory constructor Notification(String type, String message), который возвращает разные подтипы уведомлений в зависимости от параметра type:
      • Если type имеет значение 'email', верните EmailNotification
      • Если type имеет значение 'sms', верните SMSNotification
      • В противном случае верните PushNotification
    • method send(), который выводит Sending: [message]

В том же файле создайте три подкласса, которые расширяют Notification:

  • EmailNotification: Переопределите send(), чтобы выводить Email: [message]
  • SMSNotification: Переопределите send(), чтобы выводить SMS: [message]
  • PushNotification: Переопределите send(), чтобы выводить Push: [message]

Каждому подклассу нужен constructor, который принимает message и передаёт его родительскому class с помощью super._internal(message).

  • main.dart: Импортируйте свой class уведомлений и создайте три уведомления с помощью factory constructor:
    • уведомление по электронной почте с message 'Welcome!'
    • SMS-уведомление с message 'Your code is 1234'
    • push-уведомление с message 'New update available'
    Вызовите send() для каждого уведомления в указанном выше порядке.

Ожидаемый вывод:

Email: Welcome!
SMS: Your code is 1234
Push: New update available

Попробуйте сами

import 'notification.dart';

void main() {
  // TODO: Создать email-уведомление с сообщением 'Welcome!'
  
  // TODO: Create an SMS notification with message 'Your code is 1234'
  
  // TODO: Create a push notification with message 'New update available'
  
  // TODO: Вызвать send() для каждого уведомления по порядку
}
quiz iconПроверьте себя

В этом уроке есть небольшой тест. Начните урок, чтобы ответить на вопросы и сохранить прогресс.

Все уроки раздела Объектно-ориентированное программирование

Потренируйтесь самостоятельно: Онлайн-компилятор Dart