Двойной узор
В разработке программного обеспечения шаблон Twin — это шаблон проектирования программного обеспечения , который позволяет разработчикам моделировать множественное наследование в языках программирования, которые не поддерживают множественное наследование. Этот шаблон позволяет избежать многих проблем, связанных с множественным наследованием. [1]
Определение
[ редактировать ]Вместо одного класса, производного от двух суперклассов, создайте два отдельных подкласса, каждый из которых происходит от одного из двух суперклассов. Эти два подкласса тесно связаны, поэтому оба можно рассматривать как объект-близнец, имеющий два конца. [1]
Применимость
[ редактировать ]Двойной шаблон можно использовать:
- для моделирования множественного наследования на языке, в котором множественное наследование не поддерживается
- чтобы избежать некоторых проблем множественного наследования. [1]
Структура
[ редактировать ]Будет два или более родительских класса, которые используются для наследования. Будут подклассы, каждый из которых является производным от одного из суперклассов. Подклассы взаимно связаны через поля, и каждый подкласс может переопределять методы, унаследованные от суперкласса. Новые методы и поля обычно объявляются в одном подклассе. [1]
На следующей диаграмме показана типичная структура множественного наследования:

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

Сотрудничество
[ редактировать ]Каждый дочерний класс отвечает за протокол, унаследованный от родительского класса. Он обрабатывает сообщения этого протокола и пересылает другие сообщения своему партнерскому классу. [1]
Клиенты шаблона-двойника ссылаются на один из объектов-двойников напрямую, а на другой — через его поле-двойник. [1]
Клиенты, использующие протоколы родительских классов, взаимодействуют с объектами соответствующего дочернего класса. [1]
Пример кода
[ редактировать ]Следующий код представляет собой набросок реализации компьютерной игровой доски с движущимися шариками.
Класс игрового поля:
public class Gameboard extends Canvas {
public int width, height;
public GameItem firstItem;
…
}
Эскиз кода для класса GameItem:
public abstract class GameItem {
Gameboard board;
int posX, posY;
GameItem next;
public abstract void draw();
public abstract void click (MouseEvent e);
public abstract boolean intersects (GameItem other);
public abstract void collideWith (GameItem other);
public void check() {
GameItem x;
for (x = board.firstItem; x != null; x = x.next)
if (intersects(x))
collideWith(x);
}
public static BallItem newBall(int posX, int posY, int radius) { //method of GameBoard
BallItem ballItem = new BallItem(posX, posY, radius);
BallThread ballThread = new BallThread();
ballItem.twin = ballThread;
ballThread.twin = ballItem;
return ballItem;
}
}
Эскиз кода для класса BallItem:
public class BallItem extends GameItem {
BallThread twin;
int radius; int dx, dy;
boolean suspended;
public void draw() {
board.getGraphics().drawOval(posX - radius, posY - radius, 2 * radius, 2 * radius);
}
public void move() { posX += dx; posY += dy; }
public void click() {
if (suspended)
twin.resume();
else
twin.suspend();
suspended = ! suspended;
}
public boolean intersects (GameItem other) {
if (other instanceof Wall)
return posX - radius <= other.posX
&& other.posX <= posX + radius
|| posY - radius <= other.posY
&& other.posY <= posY + radius;
else
return false;
}
public void collideWith (GameItem other) {
Wall wall = (Wall) other;
if (wall.isVertical)
dx = - dx;
else
dy = - dy;
}
}
Эскиз кода для класса BallThread:
public class BallThread extends Thread {
BallItem twin;
public void run() {
while (true) {
twin.draw();
/*erase*/
twin.move();
twin.draw();
}
}
}
Реализация шаблона Twin
[ редактировать ]Следует рассмотреть следующие вопросы:
- Абстракция данных — классы-партнеры класса-близнеца должны быть тесно связаны, так как, вероятно, им необходим доступ к частным полям и методам друг друга. В Java этого можно достичь, поместив партнерские классы в общий пакет и обеспечив видимость пакета для необходимых полей и методов. В Модуле-3 и Обероне классы-партнеры могут быть размещены в общем модуле.
- Эффективность. Поскольку шаблон Twin использует композицию, требующую пересылки сообщений, шаблон Twin может быть менее эффективным, чем наследование. Однако, поскольку множественное наследование в любом случае немного менее эффективно, чем одиночное, накладные расходы не будут серьезной проблемой. [1] [2]
- Циклическая ссылка. Шаблон «Двойник» основан на том, что каждый двойник ссылается на другого двойника, что приводит к сценарию циклической ссылки. Некоторые языки могут требовать специальной обработки таких циклических ссылок во избежание утечки памяти . Например, может потребоваться сделать одну ссылку «слабой», чтобы позволить циклу разорваться.
См. также
[ редактировать ]- Шаблон адаптера , особенно двусторонний адаптер
Ссылки
[ редактировать ]- ^ Перейти обратно: а б с д и ж г час я дж к л м н Мессенбёк, Х., «Твин — шаблон проектирования для моделирования множественного наследования» , Университет Линца, Институт системного программного обеспечения.
- ^ Страуструп, Б. (май 1989 г.), Множественное наследование для C++ , Хельсинки: материалы весенней конференции EUUG.