Tehtaan menetelmä - Factory method pattern
In class-ohjelmointi , The tehdas menetelmä malli on creational malli , joka käyttää tehtaan menetelmiä käsitellä ongelmaa luomalla esineitä ilman täsmällisen luokan esineen, joka luodaan. Tämä tapahtuu luomalla esineitä soittamalla tehdas menetelmä, joko määritelty käytettäessä rajapinnan ja toteutetaan lapsi luokkia, tai toteutetaan emäksen luokan ja mahdollisesti ohittaa mukaan johdettu luokkiin-pikemminkin kuin soittamalla rakentaja .
Yleiskatsaus
Factory Method -suunnittelumalli on yksi kaksikymmentäkolmesta tunnetusta "Gang of Four" -mallista, jotka kuvaavat kuinka ratkaista toistuvat suunnitteluongelmat suunnitellakseen joustavia ja uudelleenkäytettäviä olio-ohjelmistoja, eli kohteita, jotka on helpompi toteuttaa, muuttaa, testata ja käyttää uudelleen.
Factory Method -suunnittelumalli ratkaisee seuraavat ongelmat:
- Kuinka objekti voidaan luoda niin, että alaluokat voivat määrittää uudelleen, mikä luokka luodaan?
- Kuinka luokka voi lykätä välityksiä alaluokkiin?
Tehdasmenetelmän suunnittelumalli kuvaa tällaisten ongelmien ratkaisemisen:
- Määritä erillinen toiminto ( tehdasmenetelmä ) objektin luomiseksi.
- Luo objekti kutsumalla tehdasmenetelmää .
Tämän avulla alaluokkien kirjoittaminen voi muuttaa tapaa, jolla objekti luodaan (määritellä uudelleen, mikä luokka luodaan).
Katso myös alla oleva UML -luokkakaavio.
Määritelmä
"Määritä käyttöliittymä objektin luomiseksi, mutta anna alaluokkien päättää, mikä luokka luodaan. Tehdasmenetelmä antaa luokalle mahdollisuuden lykätä käyttämänsä suorittamista alaluokkiin." ( Neljän jengi )
Objektin luominen vaatii usein monimutkaisia prosesseja, joita ei ole tarkoituksenmukaista sisällyttää sävellysobjektiin. Objektin luominen voi johtaa merkittävään koodin päällekkäisyyteen, se voi vaatia tietoja, joita säveltävä objekti ei voi käyttää, ei ehkä tarjoa riittävää abstraktion tasoa tai se ei muuten voi olla osa säveltävän objektin huolenaiheita . Tehdasmenetelmän suunnittelumalli käsittelee nämä ongelmat määrittelemällä erillisen menetelmän objektien luomiseksi, jonka alaluokat voivat sitten ohittaa määrittäessään luotavan tuotetyypin .
Tehdasmenetelmän malli perustuu perintöön, koska objektien luominen delegoidaan alaluokkiin, jotka toteuttavat tehtaan menetelmän objektien luomiseksi.
Rakenne
UML -luokan kaavio
Yllä olevassa UML -luokkakaaviossa luokka , Creatorjoka vaatii Productobjektin, ei luo Product1luokkaa suoraan. Sen sijaan Creatorviittaukset viittaavat erilliseen factoryMethod()tuoteobjektin luomiseen, mikä tekee Creatorriippumattomaksi siitä, mikä konkreettinen luokka näytetään. Alaluokat Creatorvoivat määritellä uudelleen, mikä luokka luodaan. Tässä esimerkissä Creator1alaluokka toteuttaa abstraktin factoryMethod()luennoimalla Product1luokan.
Esimerkki
Sokkelopeliä voidaan pelata kahdessa tilassa, joista toisessa on tavalliset huoneet, jotka on yhdistetty vain viereisiin huoneisiin, ja toisessa taikahuoneissa, joissa pelaajat voidaan kuljettaa satunnaisesti.
Rakenne
Roomon perusluokka lopputuotteelle ( MagicRoomtai OrdinaryRoom). MazeGameilmoittaa abstraktin tehdasmenetelmän tällaisen perustuotteen valmistamiseksi. MagicRoomja OrdinaryRoomovat lopputuotteen toteuttavan perustuotteen alaluokkia. MagicMazeGameja OrdinaryMazeGameovat alaluokkia MazeGamelopputuotteiden valmistusmenetelmän toteuttamiseksi. Siten tehdasmenetelmät irrottavat soittajat ( MazeGame) betoniluokkien toteutuksesta. Tämä tekee "uudesta" operaattorista tarpeettoman, mahdollistaa avoimen/suljetun periaatteen noudattamisen ja tekee lopputuotteesta joustavamman muutoksen sattuessa.
Esimerkkejä toteutuksista
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();
}
}
}
Yllä olevassa koodissa voit nähdä yhden käyttöliittymän luomisen IPersonja kahden toteutuksen nimeltä Villagerja CityPerson. FactoryObjektiin syötetyn tyypin perusteella palautamme alkuperäisen konkreettisen objektin käyttöliittymänä IPerson.
Tehdasmenetelmä on vain lisä Factoryluokkaan. Se luo luokan objektin rajapintojen kautta, mutta toisaalta antaa myös alaluokan päättää, mikä luokka näytetään.
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;
}
}
Näet, että olemme käyttäneet MakeProductbetonitehtaassa. Tämän seurauksena voit helposti soittaa MakeProduct()siitä saadaksesi IProduct. Voit myös kirjoittaa mukautetun logiikkasi saatuaksesi objektin konkreettiseen tehdasmenetelmään. GetObject on abstrakti tehdaskäyttöliittymässä.
Java
Tämä Java -esimerkki on samanlainen kuin kirjassa Design Patterns .
MazeGame käyttää huoneita, mutta se asettaa vastuun huoneiden luomisesta alaluokkiin, jotka luovat konkreettisia luokkia. Tavallinen pelitila voisi käyttää tätä mallimenetelmää:
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();
}
Yllä olevassa katkelmassa MazeGamekonstruktori on mallimenetelmä, joka tekee jonkinlaisen yhteisen logiikan. Se viittaa makeRoomtehdasmenetelmään, joka kiteyttää huoneiden luomisen siten, että muita huoneita voidaan käyttää alaluokassa. Jos haluat ottaa käyttöön toisen pelitilan, jossa on maagisia huoneita, riittää ohittaa makeRoommenetelmä:
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
Seuraava esimerkki PHP: ssä seuraa tällä kertaa käyttöliittymän toteutuksia alaluokittelun sijaan (sama voidaan kuitenkin saavuttaa alakategorian avulla). On tärkeää huomata, että tehdasmenetelmä voidaan myös määritellä julkiseksi ja kutsua suoraan asiakaskoodilla (toisin kuin yllä oleva Java -esimerkki).
/* 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();
Python
Sama kuin Java -esimerkki.
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()
Käyttää
- Vuonna ADO.NET , IDbCommand.CreateParameter on esimerkki käytöstä tehtaan menetelmää yhteyden rinnakkaista luokan hierarkioita.
- Vuonna Qt , QMainWindow :: createPopupMenu on tehdas menetelmä julisti puitteet, voi ohittaa in sovelluskoodissa .
- Vuonna Java , useita tehtaita käytetään javax.xml.parsers pakkauksessa. esim. javax.xml.parsers.DocumentBuilderFactory tai javax.xml.parsers.SAXParserFactory.
- Vuonna HTML5 DOM API , Document käyttöliittymä sisältää createElement tehtaan tapa luoda erityisiä osia HTMLElement käyttöliittymän.
Katso myös
- Design Patterns , erittäin vaikutusvaltainen kirja
- Suunnittelumalli , yleiskatsaus suunnittelumalleista yleensä
- Abstrakti tehdasmalli, malli , joka toteutetaan usein tehdasmenetelmillä
- Rakentajakuvio , toinen luomiskuvio
- Mallimenetelmäkuvio , joka voi kutsua tehdasmenetelmiä
- Joshua Blochin ajatus staattisesta tehdasmenetelmästä , jolla ei hänen mukaansa ole suoraa vastetta Design Patternsissa .
Viitteet
- Martin Fowler ; Kent Beck ; John Brant ; William Opdyke ; Don Roberts (kesäkuu 1999). Refactoring: Olemassa olevan koodin suunnittelun parantaminen . Addison-Wesley. ISBN 0-201-48567-2.
- Gamma, Erich ; Helm, Richard ; Johnson, Ralph; Vlissides, John (1994). Suunnittelumallit: Uudelleenkäytettävän olio-ohjelmiston elementtejä . Addison-Wesley. ISBN 0-201-63361-2.
- Cox, Brad J. (1986). Kohdekeskeinen ohjelmointi: evoluutiomainen lähestymistapa . Addison-Wesley. ISBN 978-0-201-10393-9.
- Cohen, Tal; Gil, Joseph (2007). "Parempi rakentaminen tehtaiden kanssa" (PDF) . Objektitekniikan lehti . Bertrand Meyer . 6 (6): 103. doi : 10.5381/jot.2007.6.6.a3 . Haettu 2007-03-12 .
Ulkoiset linkit
- Tehtaan suunnittelumallin toteutus Javassa
- Tehdasmenetelmä UML: ssä ja LePUS3: ssa (suunnittelun kuvauskieli)
- Harkitse Joshua Blochin staattisia tehdasmenetelmiä
