ООП для чайников. Паттерны проектирования. Паттерн абстрактная фабрика (Abstract factory)
Сегодня мы рассмотрим паттерн абстрактная фабрика, или фабрика, как его часто называют. Этот паттерн относится к группе порождающих и решает проблему создания группы объектов. Классический пример использования фабрики для предоставления приложению элементов интерфейса в зависимости от платформы. Например, приложение на linux будет создавать при помощи фабрики кнопки, поля и прочие элементы через фабрику, которая в свою очередь, по запросу будет возвращать элементы XWindows, а приложение на windows будет возвращать элементы win32. Таким образом программе становится не важна платформа, платформо-зависимая логика ляжет на плечи фабрики.
Паттерн абстрактная фабрика должен использоваться тогда когда:
- Конкретный вариант требуемого поведения системы дают не отдельные объекты, а четко выраженное семейство связанных объектов
- Объекты одного семейства должны использоваться вместе
- Система должна кофигурироваться одним из семейств объектов
Вот как это выглядит на диаграмме:
В моем примере фабрики мы имеем три вида игровых юнитов Protos, Terran, Zerg (должно быть близко любому кто играл в StarCraft), и некоторое количество игровых юнитов (ботов). Боты создают солдатов нужного типа в зависимости от количества ресурсов добытых работягами, а также боты могут сражаться друг с другом теми юнитами, что были созданы.
Вот код примера, несколько многословный, в силу специфичности синтаксиса явы:
// IUnit.java package patterns.factory.unit; public interface IUnit { public int getGroundWeapon(); public int getAirWeapon(); public int getShield(); public int getPrice(); public String toString(); } // CustomUnit.java package patterns.factory.unit; public class CustomUnit implements IUnit { @Override public int getAirWeapon() { return 0; } @Override public int getGroundWeapon() { return 0; } @Override public int getPrice() { return 0; } @Override public int getShield() { return 0; } public String toString() { return "a:" + getAirWeapon() + " g:" + getGroundWeapon() + " s:" + getShield() + " p:" + getPrice(); } } // ProtosSoldier.java package patterns.factory.unit; public class ProtosSoldier extends CustomUnit implements IUnit { @Override public int getAirWeapon() { return 10; } @Override public int getGroundWeapon() { return 12; } @Override public int getPrice() { return 100; } @Override public int getShield() { return 10; } } // Terransoldier.java package patterns.factory.unit; public class TerranSoldier extends CustomUnit implements IUnit { @Override public int getPrice() { return 35; } @Override public int getAirWeapon() { return 5; } @Override public int getGroundWeapon() { return 8; } @Override public int getShield() { return 3; } } // ZergSoldier.java package patterns.factory.unit; public class ZergSoldier extends CustomUnit implements IUnit { @Override public int getAirWeapon() { return 0; } @Override public int getGroundWeapon() { return 6; } @Override public int getPrice() { return 25; } @Override public int getShield() { return 5; } } // IArmyFactory.java package patterns.factory.army; import patterns.factory.unit.IUnit; public interface IArmyFactory { public IUnit createSoldier(); } // ProtosArmy.java package patterns.factory.army; import patterns.factory.unit.IUnit; import patterns.factory.unit.ProtosSoldier; public class ProtosArmy implements IArmyFactory { @Override public IUnit createSoldier() { return new ProtosSoldier(); } } // TerranArmy.java package patterns.factory.army; import patterns.factory.unit.IUnit; import patterns.factory.unit.TerranSoldier; public class TerranArmy implements IArmyFactory { @Override public IUnit createSoldier() { return new TerranSoldier(); } } // ZergArmy.java package patterns.factory.army; import patterns.factory.unit.IUnit; import patterns.factory.unit.ZergSoldier; public class ZergArmy implements IArmyFactory { @Override public IUnit createSoldier() { return new ZergSoldier(); } } // BotClient.java package patterns.factory.client; import java.util.ArrayList; import java.util.Iterator; import patterns.factory.army.IArmyFactory; import patterns.factory.unit.IUnit; public class BotClient { private ArrayList <IUnit> units; private IArmyFactory factory; public BotClient(IArmyFactory army) { factory = army; units = new ArrayList <IUnit> (); } public void createForMoney(int money) { Boolean hasMoney = false; units.clear(); do { IUnit unit = factory.createSoldier(); hasMoney = money - unit.getPrice() > 0; if(hasMoney){ units.add(unit); money -= unit.getPrice(); } } while(hasMoney); } public int getGroundWeapon() { int total = 0; Iterator iter = units.iterator(); while (iter.hasNext()) { total += ((IUnit)iter.next()).getGroundWeapon(); } return total; } public int getShield() { int total = 0; Iterator iter = units.iterator(); while (iter.hasNext()) { total += ((IUnit)iter.next()).getShield(); } return total; } public int unitsCount() { return units.size(); } public Boolean battle(BotClient client) { System.out.println("Units: " + unitsCount() + " vs " + client.unitsCount()); System.out.println("Attack: " + getGroundWeapon() + " vs " + client.getGroundWeapon()); System.out.println("Shield: " + getShield() + " vs " + client.getShield()); float damage = (float)client.getGroundWeapon() / (float)getShield(); System.out.println("Damage: " + damage); float enemyDamage = (float)getGroundWeapon() / (float)client.getShield(); System.out.println("Enemy damage: " + enemyDamage); return enemyDamage < damage; } } // TestApp.java package patterns.factory; import patterns.factory.army.ProtosArmy; import patterns.factory.army.TerranArmy; import patterns.factory.army.ZergArmy; import patterns.factory.client.BotClient; public class TestApp { public static void main(String[] args) { BotClient bot1 = new BotClient(new ProtosArmy()); BotClient bot2 = new BotClient(new TerranArmy()); BotClient bot3 = new BotClient(new ZergArmy()); bot1.createForMoney(400); bot2.createForMoney(400); bot3.createForMoney(400); System.out.println(bot1.battle(bot2)); System.out.println(bot1.battle(bot3)); } }
Результат работы примера:
Units: 3 vs 11 Attack: 36 vs 88 Shield: 30 vs 33 Damage: 2.9333334 Enemy damage: 1.0909091 false Units: 3 vs 15 Attack: 36 vs 90 Shield: 30 vs 75 Damage: 3.0 Enemy damage: 0.48 false
О статье
Вы сейчас читаете статью «ООП для чайников. Паттерны проектирования. Паттерн абстрактная фабрика (Abstract factory)»
- Написанную:
- 09.05.2010
- Категории:
- oop, programming

5 Комментариев
Перейти к форме добавления комментария | comments rss[?] | trackback uri [?]