Gyári módszer minta - Factory method pattern

Az osztály-alapú programozás , a gyári módszer mintázat egy létrehozási minta , amely felhasználások gyári módszerekkel kell kezelni a problémát, az objektumok létrehozásához , anélkül, hogy pontosan meghatározza az osztály az objektum jön létre. Ez úgy történik, hogy a konstruktor hívása helyett objektumokat hozunk létre gyári metódus meghívásával - vagy egy interfészben megadva, és a gyermekosztályok által megvalósítva, vagy egy alaposztályban, és adott esetben felülírva a származtatott osztályokkal .

Áttekintés

A Factory Method tervezési minta egyike annak a huszonhárom jól ismert "Gang of Four" tervezési mintának, amelyek leírják, hogyan lehet megoldani az ismétlődő tervezési problémákat, hogy rugalmas és újrafelhasználható objektum-orientált szoftvereket tervezzünk, vagyis olyan objektumokat, amelyeket könnyebb megvalósítani, változtatni, tesztelni és újra felhasználni.

A gyári módszer tervezési mintája megoldja az alábbi problémákat:

  • Hogyan hozható létre egy objektum, hogy az alosztályok újradefiniálhassák, melyik osztályt kell példányosítani?
  • Hogyan tudja az osztály elhalasztani a példányosítást az alosztályokra?

A gyári módszer tervezési mintája leírja az ilyen problémák megoldásának módját:

  • Adjon meg egy külön műveletet ( gyári módszer ) az objektum létrehozásához.
  • Hozzon létre egy objektumot egy gyári metódus meghívásával .

Ez lehetővé teszi, hogy az alosztályok írása megváltoztassa az objektum létrehozásának módját (újradefiniálja, melyik osztályt kell példányosítani).
Lásd még az alábbi UML osztálydiagramot.

Meghatározás

"Definiáljon egy felületet egy objektum létrehozásához, de hagyja, hogy az alosztályok eldöntsék, melyik osztályt kell példányosítani. A Factory módszer lehetővé teszi, hogy az osztály elhalasztja az általa használt példányosítást az alosztályokra." ( Gang Of Four )

Egy objektum létrehozása gyakran bonyolult folyamatokat igényel, amelyeket nem célszerű beépíteni a komponáló objektumba. Az objektum létrehozása a kód jelentős duplikációjához vezethet, szükség lehet olyan információkra, amelyek nem érhetők el az alkotó objektum számára, nem biztosítanak kellő mértékű absztrakciót, vagy más módon nem lehetnek részei a komponáló objektum aggályainak . A gyári metódus tervezési minta ezeket a problémákat úgy kezeli, hogy külön módszert határoz meg az objektumok létrehozására, amelyet az alosztályok ezután felülírhatnak a létrehozandó termék típusának megadásához .

A gyári metódusminta az öröklődésre támaszkodik, mivel az objektumok létrehozását olyan alosztályokra delegálják, amelyek megvalósítják a gyári metódust az objektumok létrehozásához.

Szerkezet

UML osztály diagram

Image
Minta UML osztálydiagram a Factory Method tervezési mintához.

A fenti UML osztály diagram , a Creatorosztály, amely megköveteli a Producttárgy nem példányosítunk az Product1osztály közvetlenül. Ehelyett a Creatorhivatkozás egy külön elemre utal, factoryMethod()hogy létrehozzon egy termékobjektumot, ami Creatorfüggetlenné teszi, hogy melyik konkrét osztály kerül példányosításra. Az alosztályok Creatorújradefiniálhatják, hogy melyik osztályt kell példányosítani. Ebben a példában az Creator1alosztály az absztraktot factoryMethod()az Product1osztály példányosításával valósítja meg .

Példa

A labirintus játék két módban játszható, az egyik normál szobákkal, amelyek csak a szomszédos szobákkal vannak összekötve, a másik pedig a varázslatos szobákkal, amelyek lehetővé teszik a játékosok véletlenszerű szállítását.

Szerkezet

Új WikiFactoryMethod.png

Rooma végtermék ( MagicRoomvagy OrdinaryRoom) alaposztálya . MazeGamedeklarálja az ilyen alaptermék előállításának absztrakt gyári módszerét. MagicRoomés OrdinaryRooma végterméket megvalósító alaptermék alosztályai. MagicMazeGameés a végtermékeket előállító gyári módszer megvalósításának OrdinaryMazeGamealosztályai MazeGame. Így a gyári módszerek leválasztják a hívókat ( MazeGame) a betonosztályok megvalósításáról. Ez feleslegessé teszi az "új" üzemeltetőt, lehetővé teszi a nyitott/zárt elv betartását, és rugalmasabbá teszi a végterméket változás esetén.

Példák megvalósításokra

C#

// Empty vocabulary of actual object
public interface IPerson
{
    string GetName();
}

public class Villager : IPerson
{
    public string GetName()
    {
        return "Village Person";
    }
}

public class CityPerson : IPerson
{
    public string GetName()
    {
        return "City Person";
    }
}

public enum PersonType
{
    Rural,
    Urban
}

/// <summary>
/// Implementation of Factory - Used to create objects.
/// </summary>
public class Factory
{
    public IPerson GetPerson(PersonType type)
    {
        switch (type)
        {
            case PersonType.Rural:
                return new Villager();
            case PersonType.Urban:
                return new CityPerson();
            default:
                throw new NotSupportedException();
        }
    }
}

A fenti kódban látható egy interfész létrehozása IPersonés két megvalósítás, az úgynevezett Villagerés CityPerson. Az Factoryobjektumba adott típus alapján az eredeti konkrét objektumot adjuk vissza felületként IPerson.

A gyári módszer csak kiegészítés az Factoryosztályhoz. Interfészeken keresztül hozza létre az osztály objektumát, de másrészt lehetővé teszi az alosztály számára annak eldöntését is, hogy melyik osztály kerül példányosításra.

public interface IProduct
{
    string GetName();
    bool SetPrice(double price);
}

public class Phone : IProduct
{
    private double _price;

    public string GetName()
    {
        return "Apple TouchPad";
    }

    public bool SetPrice(double price)
    {
        _price = price;
        return true;
    }
}

/* Almost same as Factory, just an additional exposure to do something with the created method */
public abstract class ProductAbstractFactory
{
    protected abstract IProduct MakeProduct();

    public IProduct GetObject() // Implementation of Factory Method.
    {
        return this.MakeProduct();
    }
}

public class PhoneConcreteFactory : ProductAbstractFactory
{
    protected override IProduct MakeProduct()
    {
        IProduct product = new Phone();
        // Do something with the object after you get the object.
        product.SetPrice(20.30);
        return product;
    }
}

Láthatjuk, hogy MakeProducta Betongyárban használtunk . Ennek eredményeként könnyen hívhat MakeProduct()tőle, hogy megkapja a IProduct. Az egyéni logikát azután is megírhatja, hogy az objektumot begyűjtötte a konkrét gyári módszerbe. A GetObject a Factory felületén elvont.

Jáva

Ez a Java példa hasonló a Design Patterns című könyv példájához .

A MazeGame szobákat használ, de a szobák létrehozásának felelősségét a konkrét osztályokat létrehozó alosztályaira helyezi. A normál játékmód ezt a sablon módszert használhatja:

public abstract class Room {
    abstract void connect(Room room);
}

public class MagicRoom extends Room {
    public void connect(Room room) {}
}

public class OrdinaryRoom extends Room {
    public void connect(Room room) {}
}

public abstract class MazeGame {
     private final List<Room> rooms = new ArrayList<>();

     public MazeGame() {
          Room room1 = makeRoom();
          Room room2 = makeRoom();
          room1.connect(room2);
          rooms.add(room1);
          rooms.add(room2);
     }

     abstract protected Room makeRoom();
}

A fenti részletben a MazeGamekonstruktor egy sablon módszer , amely közös logikát hoz létre. Ez a makeRoomgyári módszerre vonatkozik, amely a helyiségek létrehozását foglalja magában, így más helyiségek is használhatók egy alosztályban. A másik játékmód megvalósításához, amely varázslatos szobákkal rendelkezik, elegendő a makeRoommódszer felülbírálása :

public class MagicMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new MagicRoom();
    }
}

public class OrdinaryMazeGame extends MazeGame {
    @Override
    protected Room makeRoom() {
        return new OrdinaryRoom();
    }
}

MazeGame ordinaryGame = new OrdinaryMazeGame();
MazeGame magicGame = new MagicMazeGame();

PHP

A PHP másik példája következik, ezúttal interfész megvalósításokat használva az alosztályozással szemben (azonban ugyanez elérhető alosztályozással). Fontos megjegyezni, hogy a gyári metódus nyilvánosként is definiálható, és közvetlenül hívható a kliens kódjával (ellentétben a fenti Java példával).

/* Factory and car interfaces */

interface CarFactory
{
    public function makeCar(): Car;
}

interface Car
{
    public function getType(): string;
}

/* Concrete implementations of the factory and car */

class SedanFactory implements CarFactory
{
    public function makeCar(): Car
    {
        return new Sedan();
    }
}

class Sedan implements Car
{
    public function getType(): string
    {
        return 'Sedan';
    }
}

/* Client */

$factory = new SedanFactory();
$car = $factory->makeCar();
print $car->getType();

Piton

Ugyanaz, mint a Java példája.

from abc import ABC, abstractmethod


class MazeGame(ABC):
    def __init__(self) -> None:
        self.rooms = []
        self._prepare_rooms()

    def _prepare_rooms(self) -> None:
        room1 = self.make_room()
        room2 = self.make_room()

        room1.connect(room2)
        self.rooms.append(room1)
        self.rooms.append(room2)

    def play(self) -> None:
        print('Playing using "{}"'.format(self.rooms[0]))

    @abstractmethod
    def make_room(self):
        raise NotImplementedError("You should implement this!")


class MagicMazeGame(MazeGame):
    def make_room(self):
        return MagicRoom()


class OrdinaryMazeGame(MazeGame):
    def make_room(self):
        return OrdinaryRoom()


class Room(ABC):
    def __init__(self) -> None:
        self.connected_rooms = []

    def connect(self, room) -> None:
        self.connected_rooms.append(room)


class MagicRoom(Room):
    def __str__(self):
        return "Magic room"


class OrdinaryRoom(Room):
    def __str__(self):
        return "Ordinary room"


ordinaryGame = OrdinaryMazeGame()
ordinaryGame.play()

magicGame = MagicMazeGame()
magicGame.play()

Felhasználások

  • Az ADO.NET , IDbCommand.CreateParameter egy példa a használatát gyári módszerrel csatlakoztathatja párhuzamos osztály hierarchiát.
  • A Qt -ban a QMainWindow :: createPopupMenu egy gyári módszer, amelyet egy olyan keretrendszerben deklaráltak, amely felülírható az alkalmazáskódban .
  • A Java -ban több gyárat használnak a javax.xml.parsers csomagban. pl. javax.xml.parsers.DocumentBuilderFactory vagy javax.xml.parsers.SAXParserFactory.
  • A HTML5 DOM API -ban a Dokumentum felület egy createElement gyári módszert tartalmaz a HTMLElement felület egyes elemeinek létrehozásához.

Lásd még

Hivatkozások

Külső linkek