Согласно GoF, намерение шаблона Абстрактной фабрики заключается в предоставлении интерфейса для создания семейств связанных или зависимых объектов без указания их классов классов.
В каркасах абстрактные фабрики обычно предоставляются с использованием внедрения зависимостей , и это реальный ключ для написания кода, который легко тестировать. Внедрение зависимостей просто означает, что зависимости «внедряются» через конструктор, а не обновляются внутри класса.
Предположим, вы используете две фабрики для производства зависимостей (здесь только одна зависимость, Dice) для простых и сложных игр в нарды:
public class EasyGameFactory implements GameFactory
{
Dice createDice()
{
return new LuckyDice();
}
}
public class NormalGameFactory implements GameFactory
{
Dice createDice()
{
return new RandomDice();
}
}
Для целей модульного тестирования вы действительно предпочитаете не использовать ни одну из реализаций Dice, поэтому вы пишете специальную реализацию GameFactory:
public class CustomGameFactory implements GameFactory
{
private Dice mDice;
public CustomGameFactory(Dice dice)
{
mDice = dice;
}
Dice createDice()
{
return mDice;
}
}
Эта фабрика не должна быть частью вашего производственного кода. Вы снабжаете фабрику специальной реализацией Dice с помощью тестового кода:
public class TestBackgammon
{
@Test public void shouldReturnDiceThrown()
{
SettableDice dice = new SettableDice();
Game game = new GameImpl(new CustomGameFactory(dice));
dice.setDice(new int[] {4, 5});
game.nextTurn();
assertArrayEquals(new int[] {4, 5}, game.diceThrown());
}
}
При таком подходе любая конкретная зависимость может быть введена для целей тестирования. Однако часто того же самого можно достичь без абстрактной фабрики, т. Е. Вместо внедрения фабрики может быть введена сама зависимость.