Абстрактная фабрика (Abstract Factory)

Материал из Вики ИТ мехмата ЮФУ
Перейти к: навигация, поиск

К основной странице курса

Назначение

Предоставляет интерфейс для создания компонентов системы.

Другое название

Инструментарий (Kit)

Описание

В проекте с многими объектами может возникнуть необходимость менять поведение этих объектов в совокупности. Например, при переносе библиотеки графических компонентов на другую операционную систему полностью меняется реализация этих компонентов.

В этом случае можно создать абстрактный класс AbstractFactory, который будет содержать методы создания компонентов каждого вида, а в подклассах переопределить эти методы, вызывая создание конкретных компонентов (в нашем примере каждый подкласс будет ответственен за создание компонентов, связанных с одной операционной системой).

Это позволяет не менять клиентский код приложения, работающего с компонентами и обеспечивает переносимость.

Использование

Паттерн Абстрактная фабрика используется когда:

  • Система должна конфигурироваться одним из семейств составляющих ее объектов
  • Необходимо создать набор объектов, открывая только их интерфейсы

Реализация

Диаграмма классов

AbstractCommon.png

Участники

  • AbstractFactory - абстрактная фабрика

Определяет интерфейс для операций, создающих абстрактные продукты

  • ConcreteFactory - конкретная фабрика

Реализует операции, создавая конкретные продукты

  • AbstractProduct - абстрактный продукт

Определяет интерфейс для типа продукта

  • ConcreteProduct - конкретный продукт

Определяет продукт, создаваемый конкретной фабрикой.

  • Client - клиент

Использует интерфейсы AbstractFactory и AbstractProduct

Код

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MazeCommon;

namespace MazeGameAbstractFactory
{
    public class MazeFactory
    {
	public virtual Maze MakeMaze()
	{ 
            return new Maze(); 
        }
	public virtual Wall MakeWall()
	{ 
            return new Wall(); 
        }
	public virtual Room MakeRoom(int n)
	{ 
            return new Room(n); 
        }
	public virtual Door MakeDoor(Room r1, Room r2)
	{ 
            return new Door(r1,r2); 
        }
    };

    public class MazeGame
    {
        public Maze CreateMaze(MazeFactory f) 
        {
	    Maze aMaze = f.MakeMaze();
	    Room r1 = f.MakeRoom(1);
	    Room r2 = f.MakeRoom(2);
	    Door d = f.MakeDoor(r1,r2);

	    aMaze.AddRoom(r1);
	    aMaze.AddRoom(r2);

	    r1.SetSide(Direction.North, f.MakeWall());
            r1.SetSide(Direction.East, d);
            r1.SetSide(Direction.South, f.MakeWall());
            r1.SetSide(Direction.West, f.MakeWall());
            r2.SetSide(Direction.North, f.MakeWall());
            r2.SetSide(Direction.East, f.MakeWall());
            r2.SetSide(Direction.South, f.MakeWall());
            r2.SetSide(Direction.West, d);

	    return aMaze;
        }
    }

    public class BombedWall: Wall
    {
    }

    public class RoomWithABomb: Room
    {
        public RoomWithABomb(int n): base(n)
        { }
    }

    public class BombedMazeFactory : MazeFactory
    {
	    
        public override Room MakeRoom(int n)
	{ 
            return new RoomWithABomb(n); 
        }
        public override Wall MakeWall()
	{ 
            return new BombedWall(); 
        }
    };


    public class ProgramAbstractFactory
    {
        static void Main(string[] args)
        {
            Console.WriteLine("AbstractFactory");
            MazeGame game = new MazeGame();
            BombedMazeFactory f = new BombedMazeFactory();
            game.CreateMaze(f);
        }
    }
}

Достоинства и недостатки

  • Изолирует клиента от деталей реализации классов
  • Упрощает замену семейства продуктов
  • Недостаток: поддержка нового вида продукта трудна

Варианты

  • Вместо создания разных семейств продуктов в подклассах абстрактной фабрики - в самой фабрике во все методы передавать идентификатор семейства создаваемых продуктов