Двойной узор - Twin pattern

В программная инженерия, то Двойной узор это шаблон разработки программного обеспечения что позволяет разработчикам моделировать множественное наследование в языках программирования, не поддерживающих множественное наследование. Этот шаблон позволяет избежать многих проблем с множественным наследованием.[1]

Определение

Вместо того, чтобы иметь один класс, производный от двух суперклассов, иметь два отдельных подкласса, каждый производный от одного из двух суперклассов. Эти два подкласса тесно связаны, поэтому оба могут рассматриваться как объект Twin, имеющий два конца.[1]

Применимость

Двойной паттерн можно использовать:

  • для моделирования множественного наследования на языке, в котором множественное наследование не поддерживается
  • чтобы избежать некоторых проблем множественного наследования.[1]

Структура

Будет два или более родительских класса, которые используются для наследования. Будут подклассы, каждый из которых является производным от одного из суперклассов. Подклассы взаимно связаны через поля, и каждый подкласс может переопределить методы, унаследованные от суперкласса. Новые методы и поля обычно объявляются в одном подклассе.[1]

На следующей диаграмме показана типичная структура множественного наследования:

Типичное множественное наследование

[1]

На следующей диаграмме показана структура шаблона Twin после замены предыдущей структуры множественного наследования:

Двойной узор

[1]

Сотрудничество

Каждый дочерний класс отвечает за протокол, унаследованный от своего родителя. Он обрабатывает сообщения из этого протокола и пересылает другие сообщения своему классу-партнеру.[1]

Клиенты двойного паттерна ссылаются на один из двойных объектов напрямую, а другой через его двойное поле.[1]

Клиенты, которые полагаются на протоколы родительских классов, взаимодействуют с объектами соответствующего дочернего класса.[1]

Образец кода

Следующий код представляет собой набросок реализации компьютерной игровой доски с движущимися шарами.

класс для игровой доски:

 общественный учебный класс Игровая доска расширяет Холст {    общественный int ширина, высота;    общественный GameItem firstItem;    }

[1]

эскиз кода для класса GameItem:

общественный Абстрактные учебный класс GameItem {    Игровая доска доска;    int posX, ПОЗИЦИЯ;    GameItem следующий;    общественный Абстрактные пустота рисовать();    общественный Абстрактные пустота щелкнуть (MouseEvent е);    общественный Абстрактные логический пересекает (GameItem Другой);    общественный Абстрактные пустота сталкиваются с (GameItem Другой);    общественный пустота проверить() {        GameItem Икс;        за (Икс = доска.firstItem; Икс != ноль; Икс = Икс.следующий)            если (пересекает(Икс)) сталкиваются с(Икс);    }    общественный статический BallItem newBall(int posX, int ПОЗИЦИЯ, int радиус) {// метод GameBoard        BallItem ballItem = новый BallItem(posX, ПОЗИЦИЯ, радиус);        BallThread ballThread = новый BallThread();        ballItem.близнец = ballThread;        ballThread.близнец = ballItem;        возвращаться ballItem;    }}

[1]

эскиз кода для класса BallItem:

общественный учебный класс BallItem расширяет GameItem {    BallThread близнец;    int радиус; int dx, dy;    логический приостановленный;    общественный пустота рисовать() {        доска.getGraphics().drawOval(posX-радиус, ПОЗИЦИЯ-радиус, 2*радиус, 2*радиус); }    общественный пустота двигаться() { posX += dx; ПОЗИЦИЯ += dy; }    общественный пустота щелкнуть() {        если (приостановленный) близнец.продолжить();        еще близнец.приостановить();        приостановленный = ! приостановленный;    }    общественный логический пересекает (GameItem Другой) {        если (Другой экземпляр стена)            возвращаться posX - радиус <= Другой.posX                && Другой.posX <= posX + радиус                || ПОЗИЦИЯ - радиус <= Другой.ПОЗИЦИЯ                && Другой.ПОЗИЦИЯ <= ПОЗИЦИЯ + радиус;        еще возвращаться ложный;    }    общественный пустота сталкиваются с (GameItem Другой) {        стена стена = (стена) Другой;        если (стена.isVertical) dx = - dx; еще dy = - dy;    }}

[1]

Эскиз кода для класса BallThread:

общественный учебный класс BallThread расширяет Нить {    BallItem близнец;    общественный пустота пробег() {        пока (истинный) {            близнец.рисовать(); /*стереть*/ близнец.двигаться(); близнец.рисовать();        }    }}

[1]

Реализация паттерна Twin

Следует учитывать следующие вопросы:

  • Абстракция данных - классы-партнеры двойного класса должны быть тесно связаны, поскольку, вероятно, они должны иметь доступ к частным полям и методам друг друга. В Java это может быть достигнуто путем помещения партнерских классов в общий пакет и обеспечения видимости пакета для требуемых полей и методов. В Модуле-3 и в Обероне партнерские классы могут быть помещены в общий модуль
  • Эффективность - поскольку в шаблоне Twin используется композиция, которая требует пересылки сообщений, шаблон Twin может быть менее эффективным, чем наследование. Однако, поскольку множественное наследование в любом случае немного менее эффективно, чем одиночное, накладные расходы не будут большой проблемой.[1][2]

Смотрите также

Рекомендации

  1. ^ а б c d е ж грамм час я j k л м п Мёссенбёк, Х., Twin - шаблон проектирования для моделирования множественного наследования, Университет Линца, Институт системного программного обеспечения
  2. ^ Страуструп, Б. (май 1989 г.), Множественное наследование для C ++, Хельсинки: Продолжение весенней конференции EUUG