Factory Method: realizare tradiţională sau Generics
Şablonul de proiectare Factory Method este un şablon frecvent utilizat în proiectarea obiect-orientată şi oferă posibilitatea ca tipul obiectului instanţiat să fie decis de subclasele Creator-ului.

Factory Method design pattern [Sursa: http://dofactory.com/Patterns]
În mod obişnuit, “clientul” fabricării obiectului este chiar Creator-ul, ce permite descendenţilor săi să redefinească metoda de “fabricare”, asigurând principiul Protected Variations definit de GRASP.
Pentru facilitarea înţelegerii, să simplificăm intenţia şablonului şi să admitem că “clientul” poate fi nu numai clasa de bază. Astfel codul sursă ce reprezintă şablonul acestuia poate fi următorul:
public abstract class Product { public Product() { } } public class ConcreteProduct : Product { public ConcreteProduct() { } } public abstract class Creator { /* Factory Method */ public abstract Product CreateProduct(); } public class ConcreteCreator: Creator { public override Product CreateProduct() { return new ConcreteProduct(); } }
Deşi codul este simplificat, el oricum arată cam “mult”
. De aici şi dorinţa firească a coder-ului să-şi “optimizeze” obiectul muncii.
Generics i-ar fi ca şi un colac de salvare, căci este cunoscut faptul că tehnicile Generics permit coduri elegante. Astfel fabrica prezentată mai sus poate fi redusă la:
public class GenericFactory where T : Product, new() { public Product CreateProduct() { return new T(); } }
Bineînţeles, nu mai este nevoie de subclasare. Mai mult decât atât, implementarea cu Generics se consideră a fi o soluţie mai eficientă, căci legarea se face în compile-time.
class Program { static void Main(string[] args) { GenericFactory genericFactory = new GenericFactory (); ConcreteCreator classicCreator = new ConcreteCreator(); Product classicProduct = classicCreator.CreateProduct(); Product genericProduct = genericFactory.CreateProduct(); } }
Pentru diverse limbaje de programare implementarea cu Generics puţin diferă, dar principiile rămîn a fi aceleaşi (Mihai Tataran(C#), jerron (C), Hugo Troche (Java), Gaston Milano (C#), etc.) Spre deosebire de mulţi Hugo Troche şi Gaston Milano menţionează în articolele lor că implementarea şablonului Factory Method cu Generics, aduce şi anumite inconveniente, pentru care oferă şi soluţii, utilizînd tot şabloanele
!
Cu toate acestea am văzut deseori recomandarea de a recurge la fabricarea obiectelor cu Generics doar ca şi un remediu de evitare a subclasării. Dar în acest caz, aş dori să văd soluţia în care fiecărui tip de obiect creat de fabrică să-i fie aplicată o politică specifică de creare… Presupun că dacă se respectă open-closed principle, atunci obligator soluţia va include şi subclasarea
!
Mai există încă un detaliu, care scapă la mulţi. În descrierea motivaţiei şablonului se recurge la exemplul unui framework în care există următoarea dilemă:
The framework must instantiate classes, but it only knows about abstract classes, which it cannot instantiate.
Şi aici soluţia recomandată este anume şablonul Factory Method în forma prezentată în GoF:
It encapsulates the knowledge of which Document (Product n.a.) subclass to create and moves this knowledge out of the framework.
Deci dacă noi substituim aici subclasarea cu un alt tip de relaţie, riscăm să pierdem esenţa şablonului Factory Method. Este adevărat că un cod “optimizat” poate fi mai eficient, dar deseori la “optimizarea” codului se uită ideea ce este menţionată şi în Design Patterns: Elements of Reusable Object-Oriented Software (Gamma şi alţii):
Dynamic, highly parameterized software is harder to understand than more static software. There are also run-time inefficiencies, but the human inefficiencies are more important in the long run.
Astfel utilzînd anumite tehnici de programare să fim atenţi ce cîştigăm, dar şi ce riscăm să pierdem.









Citind acest articol mi-am adus aminte de fraza "Optimization hinders evolution"
, si intradevar domn Ciorba, eu inteleg pentru ce este nevoie de optimizarea Sabloanelor in limbajele de nivelul Java sau C#
, care sint niste limbaje orientate mai mult spre disign.
În general, "optimizarea" codului este necesară, dar mult depinde cînd ea este realizată şi cum. Dar nu prea înţeleg de ce le zici la Java şi C# "limbaje orientate mai mult spre design"? Ce ai vrut să spui?
Am vrut sa spun sint deacord cu optimizarea codului pentru sabloanele de proiectare in limbajele care ofera multe posibilitati si flexibilitate
. Dar in unele cazuri la optimizarea se perde conceptul sablonului.
Cit despre Java si C# le spun "limbaje orientate mai mult spre design" deoarece eu le vad ca niste limbaje care folosesc mai mult reutilizarea disign-ului si programatorul este responsabil numai de implimentare.
- Domnule Ciorba, ce ati vrut sa spuneti prin fraza "Dar în acest caz, aş dori să văd soluţia în care fiecărui tip de obiect creat de fabrică să-i fie aplicată o politică specifică de creare…" ?
- In caz ca se evita subclasare, se perde posibilitatea de extindere a functionalitatilor
fabricii ?
Unui obiect este posibil de adăugat noi funcţionalităţi şi fără subclasarea directă şi acest lucru avem prezent în diverse şabloane de proiectare. În acelaşi timp cunoscutul principiu Open/Closed, indiferent de ce formă este vorba, implică subclasarea ca şi un mecanism "natural" pentru extensia funcţionalităţilor obiectelor.
.
Iar în articol am vorbit despre condiţiile de creare specializată a fiecărui obiect în parte creat de fabrică, şi dacă dorim să evitîm subclasarea ce ne facem… revenim la switch sau la diverse metode (funcţii membre) de creare
ahh, all this "Romanian" talk just reminds me how hard and sometimes weird, not to mention difficult to understand to someone, is to express technical "thoughts" in Romanian, sometimes… thought, we should still stick to our language, it's *our* language
(P.S. sorry, I seem to have forgotten the language (: )
Maybe you are right. Sometimes something is more simple to express directly in modern 'technical' English language. Therefore I don't want to be ridiculous in translating all things in Romanian.
And in same time, I don't know where are you, but we must to love our language which is live because we speak and write using it.
Dacă dorim să evităm subclasarea și cunoaștem bine mecanismul de funcționare a templaturilor (C++) (mecanism extins de generics) atunci putem defini politica de creare specifică fiecărei clase
, fără subclasare. Dar această soluție este o idiomă.
Pentru o solutie mai generală cred că ar fi vorba de dependency inversion principle.
D-le profesor, legarea compile-time se face pentru mecanismul template din C++, iar pentru generic din Java sau C#, se face run-time.
Referinta: "Professional .NET 2.0 Generics", Tod Golding, pag.36
Dicutind cu prietenii mei sablonul, am adus vorba si de acest articol, problema este pusa foarte bine. Dupa 22 de saptamini perceperea acestei probleme este radical diferita.
Da şi priveşte ce este scris şi pe IMB[Classworking toolkit: Reflecting generics, ” target=”_blank”>http://www.ibm.com/developerworks/java/library/j-...
"Generics are implemented on the Java platform as a compile-time transformation. The compiler actually generates the same bytecode instructions as would be used for non-generic source code, inserting run-time casts to convert values to the appropriate type on each access. Despite this identical bytecode, the type parameter information is recorded in the class format using a new signature attribute. The JVM records this signature information when loading a class and makes it available at run time using reflection…"
Succese!
D-le Ciorbă aceasta întrebare ar necesita ”un articol”
pentru ca să discutăm mai detaliat
, căci în contextul dat se pierde esența problemei, deoarece nu prea are importanță aici când și cum se face legătura între fabrică și produsul concret. Important aici este aceia că produsele concrete care au a fi create de fabrică, sânt supuse la aceeași politică de creare
.
PS: Observația despre legarea compile-time am făcut-o în linii generale.
Leave your response!
Aviz
Categorii
Blogroll
Recent Comments
Most Commented
Most Popular Posts