Понять разницу в мотивации:
Предположим, вы создаете инструмент, в котором есть объекты, и конкретную реализацию взаимосвязей объектов. Поскольку вы предвидите изменения в объектах, вы создали косвенное направление, возложив ответственность за создание вариантов объектов на другой объект ( мы называем это абстрактной фабрикой ). Эта абстракция находит сильное преимущество, так как вы предвидите будущие расширения, которым нужны варианты этих объектов.
Еще одна довольно интригующая мотивация в этой линии мыслей - это случай, когда каждый из объектов всей группы будет иметь соответствующий вариант. Исходя из некоторых условий, будет использоваться любой из вариантов, и в каждом случае все объекты должны быть одного варианта. Это может быть немного противоречивым для понимания, поскольку мы часто склонны думать, что - пока варианты объекта следуют общему унифицированному контракту ( интерфейс в более широком смысле ), конкретный код реализации никогда не должен нарушаться. Интересным фактом здесь является то, что не всегда это верно, особенно когда ожидаемое поведение не может быть смоделировано программным контрактом.
Простым ( заимствуя идею от GoF ) являются любые приложения с графическим интерфейсом, скажем, виртуальный монитор, который имитирует внешний вид ОС MS, Mac или Fedora. Здесь, например, когда все объекты виджета, такие как окно, кнопка и т. Д., Имеют вариант MS, за исключением полосы прокрутки, которая получена из варианта MAC, назначение инструмента не удается.
Эти вышеупомянутые случаи формируют фундаментальную потребность в абстрактной фабричной модели .
С другой стороны, представьте, что вы пишете фреймворк, чтобы многие люди могли создавать различные инструменты ( например, один из приведенных выше примеров ), используя ваш фреймворк. По самой идее фреймворка вам не нужно, хотя вы не можете использовать конкретные объекты в своей логике. Вы скорее заключаете какие-то контракты высокого уровня между различными объектами и тем, как они взаимодействуют. Пока вы ( как разработчик фреймворка ) остаетесь на очень абстрактном уровне, каждый создатель инструмента вынужден следовать вашим фреймворк-конструкциям. Тем не менее, они ( создатели инструментов ) могут свободно выбирать, какой объект будет построен и как все объекты, которые они создают, будут взаимодействовать. В отличие от предыдущего случая ( абстрактного шаблона ), вы ( как создатель фреймворка)в этом случае не нужно работать с конкретными объектами; и скорее может остаться на уровне контракта объектов. Кроме того, в отличие от второй части предыдущих мотиваций, у вас или у создателей инструментов никогда не бывает ситуаций смешивания объектов из вариантов. Здесь, в то время как код платформы остается на уровне контракта, каждый создатель инструмента ограничен ( по природе самого случая ) использованием своих собственных объектов. Создание объектов в этом случае делегируется каждому реализатору, а поставщики инфраструктуры просто предоставляют единые методы для создания и возврата объектов. Такие методы неизбежны для разработчика инфраструктуры для продолжения работы со своим кодом и имеют специальное имя, называемое фабричным методом ( Factory Method Pattern для базового шаблона ).
Несколько заметок:
- Если вы знакомы с «методом шаблона», то увидите, что фабричные методы часто вызываются из методов шаблона в случае программ, относящихся к любой форме фреймворка. Напротив, шаблонные методы прикладных программ часто представляют собой простую реализацию определенного алгоритма и лишены фабричных методов.
- Кроме того, для полноты мыслей, используя структуру ( упомянутую выше ), когда создатель инструмента создает инструмент внутри каждого метода фабрики, вместо создания конкретного объекта, он / она может далее делегировать ответственность абстрактному -фабричный объект, при условии, что инструмент-строитель предусматривает варианты конкретных объектов для будущих расширений.
Образец кода:
//Part of framework-code
BoardGame {
Board createBoard() //factory method. Default implementation can be provided as well
Piece createPiece() //factory method
startGame(){ //template method
Board borad = createBoard()
Piece piece = createPiece()
initState(board, piece)
}
}
//Part of Tool-builder code
Ludo inherits BoardGame {
Board createBoard(){ //overriding of factory method
//Option A: return new LudoBoard() //Lodu knows object creation
//Option B: return LudoFactory.createBoard() //Lodu asks AbstractFacory
}
….
}
//Part of Tool-builder code
Chess inherits BoardGame {
Board createBoard(){ //overriding of factory method
//return a Chess board
}
….
}