Bir fabrika sınıfı yerine bir nesnede fabrika yöntemlerini kullanmak ne zaman iyi bir fikirdir?
Bir fabrika sınıfı yerine bir nesnede fabrika yöntemlerini kullanmak ne zaman iyi bir fikirdir?
Yanıtlar:
Tasarım pattenlerini sınıflarımın 'insanlar' olarak düşünmeyi seviyorum ve kalıplar insanların birbirleriyle konuşma biçimleri.
Bu yüzden bana göre fabrika modeli bir işe alma ajansı gibidir. Değişken sayıda işçiye ihtiyaç duyacak birine sahipsiniz. Bu kişi, işe aldıkları kişilerde ihtiyaç duydukları bazı bilgileri bilebilir, ancak hepsi bu.
Böylece, yeni bir çalışana ihtiyaç duyduklarında, işe alım ajansını arar ve onlara neye ihtiyaçları olduğunu söylerler. Şimdi, birisini gerçekten işe almak için, birçok şey bilmeniz gerekir - faydalar, uygunluk doğrulaması, vb. Ancak işe alım yapan kişinin bunlardan herhangi birini bilmesi gerekmez - işe alım ajansı tüm bunları halleder.
Aynı şekilde, bir Fabrika kullanmak tüketicinin nasıl yaratıldıklarının veya bağımlılıklarının ne olduğunu bilmelerine gerek kalmadan yeni nesneler yaratmasına izin verir - sadece gerçekte istedikleri bilgileri vermek zorundalar.
public interface IThingFactory
{
Thing GetThing(string theString);
}
public class ThingFactory : IThingFactory
{
public Thing GetThing(string theString)
{
return new Thing(theString, firstDependency, secondDependency);
}
}
Böylece, şimdi ThingFactory tüketicisi, tüketiciden gelen dize verileri hariç, Şey'in bağımlılıkları hakkında bilgi sahibi olmak zorunda kalmadan bir Şey elde edebilir.
within an object instead of a Factory class
. Sanırım ctor özel yapmak ve sınıf (nesne oluşturmak) başlatmak için statik bir yöntem kullanmak senaryo demek. Ancak bu örneği takip etmek için ThingFactory
önce Thing
nesneyi almak için sınıfı başlatmak gerekir , bu da bunu Factory class
etkili kılar .
Fabrika yöntemleri inşaatçılara alternatif olarak düşünülmelidir - çoğunlukla inşaatçılar yeterince etkileyici olmadığında, yani.
class Foo{
public Foo(bool withBar);
}
şu kadar etkileyici değil:
class Foo{
public static Foo withBar();
public static Foo withoutBar();
}
Fabrika sınıfları, nesneyi oluşturmak için karmaşık bir sürece ihtiyaç duyduğunuzda, inşaatın gerçek sınıf için istemediğiniz bir bağımlılığa ihtiyacı olduğunda, farklı nesneler inşa etmeniz gerektiğinde yararlıdır.
Kişisel olarak anlamlı fabrika sınıfları bulduğum bir durum, yaratmaya çalıştığınız son nesnenin diğer birkaç nesneye dayandığı zamandır. Örneğin, PHP: Bir olduğunu varsayalım House
sırayla bir olduğu nesneyi, Kitchen
bir LivingRoom
nesneyi ve LivingRoom
nesne vardır TV
nesne içini de.
Bunu başarmanın en basit yöntemi, her nesnenin yapı yönteminde çocuklarını oluşturmasını sağlamaktır, ancak özellikler nispeten iç içe geçmişse, House
oluşturma başarısız olduğunuzda, muhtemelen tam olarak neyin başarısız olduğunu izole etmeye çalışmak için biraz zaman harcayacaksınız.
Alternatif aşağıdakileri yapmaktır (fantezi terimini seviyorsanız bağımlılık enjeksiyonu):
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
Burada bir House
başarısızlık yaratma süreci bakmak için sadece bir yer varsa, ancak her yeni bir istendiğinde bu parçayı kullanmak zorunda olmak House
kolay değildir. Fabrikaları Girin:
class HouseFactory {
public function create() {
$TVObj = new TV($param1, $param2, $param3);
$LivingroomObj = new LivingRoom($TVObj, $param1, $param2);
$KitchenroomObj = new Kitchen($param1, $param2);
$HouseObj = new House($LivingroomObj, $KitchenroomObj);
return $HouseObj;
}
}
$houseFactory = new HouseFactory();
$HouseObj = $houseFactory->create();
Buradaki fabrika sayesinde a oluşturma süreci House
soyutlanır (çünkü sadece a oluşturmak istediğinizde her bağımlılığı yaratmanıza ve kurmanıza gerek yoktur House
) ve aynı zamanda merkezi hale getirilir ve bu da bakımını kolaylaştırır. Ayrı Fabrikalar kullanmanın faydalı olabilmesinin başka nedenleri de vardır (örneğin test edilebilirlik), ancak Fabrika sınıflarının nasıl faydalı olabileceğini en iyi şekilde göstermek için bu özel kullanım örneğini buluyorum.
HouseFactory
sınıfa nasıl aktarılır ?
create
yöntemiyle. Örneğin House
, her zaman aynı türden olacaksa LivingRoom
, parametrelerini argüman olarak iletilmek yerine fabrika sınıfında sabit kodlamak mantıklı olabilir. Ya da birkaç çeşit siniz varsa ve her tür için sabit kodlanmış parametreleri içeren bir anahtarınız varsa type
, HouseFactory::create
yönteminize bir argüman sağlamak isteyebilirsiniz LivingRoom
.
Fabrika veya fabrika yöntemini kullanarak arkasındaki fikri açıkça ayırt etmek önemlidir. Her ikisi de birbirini dışlayan farklı türde nesne yaratma sorunlarına yöneliktir.
"Fabrika yöntemi" hakkında ayrıntılı olalım:
İlk şey, daha fazla uygulama geliştirme için kullanılacak kitaplık veya API'ler geliştirirken, fabrika yönteminin oluşturma deseni için en iyi seçimlerden biridir. Arkasındaki neden; Gerekli işlev (ler) e sahip bir nesne ne zaman oluşturulacağını, ancak nesne türünün kararsız kalacağını veya dinamik parametrelerin geçirilmesine karar verileceğini biliyoruz .
Şimdi nokta, fabrika modelinin kendisi kullanılarak yaklaşık olarak aynı şekilde elde edilebilir, ancak yukarıda vurgulanan sorun için fabrika deseni kullanılacaksa, büyük bir dezavantaj sisteme girecektir, farklı nesneleri (alt sınıf nesneleri) crating mantığınız bazı iş koşullarına özgü olun, bu nedenle gelecekte kitaplığınızın işlevselliğini diğer platformlar için genişletmeniz gerektiğinde (Daha teknik olarak, temel arayüz veya soyut sınıftan daha fazla alt sınıf eklemeniz gerekir, böylece fabrika bu nesneleri de mevcut nesnelere ek olarak döndürür bazı dinamik parametrelere dayalı olarak), daha sonra maliyetli bir işlem olacak ve tasarım açısından iyi olmayan fabrika sınıfı mantığını her zaman değiştirmeniz (genişletmeniz) gerekir. Diğer tarafta, eğer "fabrika yöntemi"
interface Deliverable
{
/*********/
}
abstract class DefaultProducer
{
public void taskToBeDone()
{
Deliverable deliverable = factoryMethodPattern();
}
protected abstract Deliverable factoryMethodPattern();
}
class SpecificDeliverable implements Deliverable
{
/***SPECIFIC TASK CAN BE WRITTEN HERE***/
}
class SpecificProducer extends DefaultProducer
{
protected Deliverable factoryMethodPattern()
{
return new SpecificDeliverable();
}
}
public class MasterApplicationProgram
{
public static void main(String arg[])
{
DefaultProducer defaultProducer = new SpecificProducer();
defaultProducer.taskToBeDone();
}
}
Aşağıdaki durumlarda nesnenin içindeki fabrika yöntemlerini kullanmak iyi bir fikirdir :
Aşağıdaki durumlarda soyut fabrika sınıfını kullanmak iyi bir fikirdir :
Gelen UML
Ürün: Factory yönteminin oluşturduğu nesnelerin bir arayüzünü tanımlar.
ConcreteProduct: Ürün arayüzünü uygular
Oluşturan: Factory yöntemini beyan eder
ConcreateCreator: ConcreteProduct örneğini döndürmek için Fabrika yöntemini uygular
Sorun bildirimi: Oyun arayüzünü tanımlayan Fabrika Yöntemlerini kullanarak bir Oyun Fabrikası oluşturun.
Kod snippet'i:
import java.util.HashMap;
/* Product interface as per UML diagram */
interface Game{
/* createGame is a complex method, which executes a sequence of game steps */
public void createGame();
}
/* ConcreteProduct implementation as per UML diagram */
class Chess implements Game{
public Chess(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Chess game");
System.out.println("Opponents:2");
System.out.println("Define 64 blocks");
System.out.println("Place 16 pieces for White opponent");
System.out.println("Place 16 pieces for Black opponent");
System.out.println("Start Chess game");
System.out.println("---------------------------------------");
}
}
class Checkers implements Game{
public Checkers(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Checkers game");
System.out.println("Opponents:2 or 3 or 4 or 6");
System.out.println("For each opponent, place 10 coins");
System.out.println("Start Checkers game");
System.out.println("---------------------------------------");
}
}
class Ludo implements Game{
public Ludo(){
}
public void createGame(){
System.out.println("---------------------------------------");
System.out.println("Create Ludo game");
System.out.println("Opponents:2 or 3 or 4");
System.out.println("For each opponent, place 4 coins");
System.out.println("Create two dices with numbers from 1-6");
System.out.println("Start Ludo game");
System.out.println("---------------------------------------");
}
}
/* Creator interface as per UML diagram */
interface IGameFactory {
public Game getGame(String gameName);
}
/* ConcreteCreator implementation as per UML diagram */
class GameFactory implements IGameFactory {
HashMap<String,Game> games = new HashMap<String,Game>();
/*
Since Game Creation is complex process, we don't want to create game using new operator every time.
Instead we create Game only once and store it in Factory. When client request a specific game,
Game object is returned from Factory instead of creating new Game on the fly, which is time consuming
*/
public GameFactory(){
games.put(Chess.class.getName(),new Chess());
games.put(Checkers.class.getName(),new Checkers());
games.put(Ludo.class.getName(),new Ludo());
}
public Game getGame(String gameName){
return games.get(gameName);
}
}
public class NonStaticFactoryDemo{
public static void main(String args[]){
if ( args.length < 1){
System.out.println("Usage: java FactoryDemo gameName");
return;
}
GameFactory factory = new GameFactory();
Game game = factory.getGame(args[0]);
if ( game != null ){
game.createGame();
System.out.println("Game="+game.getClass().getName());
}else{
System.out.println(args[0]+ " Game does not exists in factory");
}
}
}
çıktı:
java NonStaticFactoryDemo Chess
---------------------------------------
Create Chess game
Opponents:2
Define 64 blocks
Place 16 pieces for White opponent
Place 16 pieces for Black opponent
Start Chess game
---------------------------------------
Game=Chess
Bu örnek, Factory
a FactoryMethod
.
Game
tüm oyun türleri için arayüzdür. Karmaşık yöntemi tanımlar:createGame()
Chess, Ludo, Checkers
farklı uygulama varyantlarıdır. createGame()
public Game getGame(String gameName)
olduğu FactoryMethod
içinde IGameFactory
sınıfın
GameFactory
yapıcıda farklı türde oyunlar oluşturur. IGameFactory
Fabrika yöntemini uygular .
Oyun adı, komut satırı argümanı olarak NotStaticFactoryDemo
getGame
in GameFactory
bir oyun adını kabul eder ve karşılık gelen Game
nesneyi döndürür .
Fabrika:
Örnekleme mantığını istemciye göstermeden nesneler oluşturur.
FactoryMethod
Nesne oluşturmak için bir arabirim tanımlayın, ancak alt sınıfların hangi sınıfı başlatacağına karar vermesine izin verin. Fabrika yöntemi, bir sınıfın alt sınıflara örnek oluşturmayı ertelemesini sağlar
Kullanım örneği:
Ne zaman kullanılır: Client
çalışma zamanında hangi somut sınıfların oluşturulması gerektiğini bilmez, ancak sadece işi yapacak bir sınıf almak ister.
getArea()
Bir fabrika yöntemi değildir hiç .
Gerçekten bir zevk meselesi. Fabrika sınıfları gerektiği gibi soyutlanabilir / arayüzlenebilirken, fabrika yöntemleri daha hafiftir (ve tanımlanmış bir türü olmadığı için test edilebilir olma eğilimindedirler, ancak bir hizmete benzer, iyi bilinen bir kayıt noktası gerektirirler. ancak fabrika yöntemlerini bulmak için).
Fabrika sınıfları, döndürdükleri nesne türünün özel bir kurucuya sahip olması durumunda, farklı fabrika sınıfları geri dönen nesne üzerinde farklı özellikler ayarladığında veya belirli bir fabrika türü geri dönen beton tipiyle birleştirildiğinde yararlıdır.
WCF , farklı durumlarda ServiceHost nesnelerini almak için ServiceHostFactory sınıflarını kullanır. Standart ServiceHostFactory, IIS tarafından .svc dosyaları için ServiceHost örneklerini almak üzere kullanılır , ancak JavaScript istemcilerine serileştirmeler döndüren hizmetler için bir WebScriptServiceHostFactory kullanılır. ADO.NET Veri Hizmetlerinin kendi özel DataServiceHostFactory'si vardır ve hizmetlerinin özel kurucuları olduğundan ASP.NET'in ApplicationServicesHostFactory'si vardır.
Eğer fabrikayı tüketen sadece bir sınıfınız varsa, o sınıf içinde sadece bir fabrika metodu kullanabilirsiniz.
Bir Sipariş ve Müşteri sınıfı tasarlamanız gerektiğinde bir senaryo düşünün. Basitlik ve başlangıç gereksinimleri için Sipariş sınıfı için fabrikaya ihtiyaç duymazsınız ve başvurunuzu birçok 'yeni Order ()' ifadesiyle doldurursunuz. Her şey yolunda gidiyor.
Artık yeni bir gereksinim, Order nesnesinin Müşteri ilişkilendirmesi (yeni bağımlılık) olmadan somutlaştırılamayacağı ortaya çıkıyor. Şimdi aşağıdaki düşünceleriniz var.
1- Sadece yeni uygulamalar için çalışacak aşırı yük oluşturucu oluşturursunuz. (Kabul edilemez). 2- Sipariş () imzalarını ve her bir çağrıyı değiştirirsiniz. (İyi bir uygulama ve gerçek bir acı değil).
Bunun yerine Sipariş Sınıfı için bir fabrika oluşturduysanız, yalnızca bir kod satırını değiştirmeniz yeterlidir. Hemen hemen her agrega derneği için Fabrika sınıfı öneririm. Umarım yardımcı olur.
kullanım açısından farklı bir nesne oluşturmak istiyorsanız. Bu kullanışlı.
public class factoryMethodPattern {
static String planName = "COMMERCIALPLAN";
static int units = 3;
public static void main(String args[]) {
GetPlanFactory planFactory = new GetPlanFactory();
Plan p = planFactory.getPlan(planName);
System.out.print("Bill amount for " + planName + " of " + units
+ " units is: ");
p.getRate();
p.calculateBill(units);
}
}
abstract class Plan {
protected double rate;
abstract void getRate();
public void calculateBill(int units) {
System.out.println(units * rate);
}
}
class DomesticPlan extends Plan {
// @override
public void getRate() {
rate = 3.50;
}
}
class CommercialPlan extends Plan {
// @override
public void getRate() {
rate = 7.50;
}
}
class InstitutionalPlan extends Plan {
// @override
public void getRate() {
rate = 5.50;
}
}
class GetPlanFactory {
// use getPlan method to get object of type Plan
public Plan getPlan(String planType) {
if (planType == null) {
return null;
}
if (planType.equalsIgnoreCase("DOMESTICPLAN")) {
return new DomesticPlan();
} else if (planType.equalsIgnoreCase("COMMERCIALPLAN")) {
return new CommercialPlan();
} else if (planType.equalsIgnoreCase("INSTITUTIONALPLAN")) {
return new InstitutionalPlan();
}
return null;
}
}
Çalışması gereken nesne için nesne oluşturmayı alt sınıfına erteleyen herhangi bir sınıf, Fabrika modelinin bir örneği olarak görülebilir.
Https://stackoverflow.com/a/49110001/504133 adresindeki başka bir yanıtta ayrıntılı olarak bahsetmiştim.
Kodunuza getirmek istediğiniz gevşek bağlantı derecesine bağlı olacağını düşünüyorum.
Fabrika yöntemi işleri çok iyi ayırır, ancak fabrika sınıfı no.
Başka bir deyişle, fabrika yöntemini kullanırsanız, basit bir fabrika (fabrika sınıfı olarak bilinir) kullanmanız yerine işleri değiştirmek daha kolaydır.
Şu örneğe bakın: https://connected2know.com/programming/java-factory-pattern/ . Şimdi, yeni bir Hayvan getirmek istediğinizi düşünün. Fabrika sınıfında Fabrikayı değiştirmeniz gerekir, ancak fabrika yönteminde hayır, sadece yeni bir alt sınıf eklemeniz gerekir.
Fabrika sınıfları daha ağırdır, ancak size bazı avantajlar sağlar. Nesnelerinizi birden çok ham veri kaynağından oluşturmanız gerektiğinde, bunlar yalnızca bina mantığını (ve belki de verilerin toplanmasını) tek bir yerde kapsüllemenize izin verir. Orada nesne arayüzü ile ilgilenmeden soyut olarak test edilebilir.
Bu yararlı bir desen buldum, özellikle ben ORM değiştiremiyorum ve yetersiz ve verimli bir şekilde DB tablo birleşimler veya saklı yordamlar birçok nesne somutlaştırmak istiyorum.
Fabrikaları kütüphane kavramına benzetiyorum. Örneğin, sayılarla çalışmak için bir kütüphane ve şekillerle çalışmak için başka bir kütüphaneniz olabilir. Bu kütüphanelerin işlevlerini mantıksal olarak adlandırılmış dizinlerde Numbers
veya olarak saklayabilirsiniz.Shapes
. Bunlar, şekillerde tamsayılar, şamandıralar, dobüller, uzun veya dikdörtgenler, daireler, üçgenler, beşgenleri içerebilen genel türlerdir.
Fabrika petter polimorfizm, bağımlılık enjeksiyonu ve kontrolün tersini kullanır.
Fabrika Kalıplarının belirtilen amacı: Define an interface for creating an object, but let subclasses decide which class to instantiate. Factory Method lets a class defer instantiation to subclasses.
Diyelim ki bir İşletim Sistemi veya Çerçeve oluşturuyorsunuz ve tüm ayrık bileşenleri oluşturuyorsunuz.
İşte PHP'deki Fabrika Kalıbı kavramına basit bir örnek. Hepsinde% 100 olmayabilirim ama basit bir örnek olarak sunulması amaçlanıyor. Ben uzman değilim.
class NumbersFactory {
public static function makeNumber( $type, $number ) {
$numObject = null;
$number = null;
switch( $type ) {
case 'float':
$numObject = new Float( $number );
break;
case 'integer':
$numObject = new Integer( $number );
break;
case 'short':
$numObject = new Short( $number );
break;
case 'double':
$numObject = new Double( $number );
break;
case 'long':
$numObject = new Long( $number );
break;
default:
$numObject = new Integer( $number );
break;
}
return $numObject;
}
}
/* Numbers interface */
abstract class Number {
protected $number;
public function __construct( $number ) {
$this->number = $number;
}
abstract public function add();
abstract public function subtract();
abstract public function multiply();
abstract public function divide();
}
/* Float Implementation */
class Float extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Integer Implementation */
class Integer extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Short Implementation */
class Short extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Double Implementation */
class Double extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
/* Long Implementation */
class Long extends Number {
public function add() {
// implementation goes here
}
public function subtract() {
// implementation goes here
}
public function multiply() {
// implementation goes here
}
public function divide() {
// implementation goes here
}
}
$number = NumbersFactory::makeNumber( 'float', 12.5 );
NumbersFactory::makeNumber( 'float', 12.5 );
Bana new Float(12.5);
ihtiyacım olduğunu bildiğimde bana ne veriyor Float
? Fabrikalar hakkında anlamadığım şey budur ... amaç ne?