Աբստրակտ ֆաբրիկա (նախագծման ձևանմուշ)

Աբստրակտ ֆաբրիկա նախագծման ձևանմուշը իրենից ներկայացնում է առանձին ֆաբրիկաների ինկապսուլյացայի մեթոդ, որտեղ վերոհիշյալ ֆաբրիկաներն ունեն ընդհանուր թեմատիկա՝ առանց իրենց կոնկրետ դասերը մատնանշելու[2]։ Սովորական օգտագործման դեպքում ծրագրային ապահովումը ստեղծում է աբստրակտ ֆաբրիկայի կոնկրետ իրականացում, իսկ այնուհետև ընդհանուր ինտերֆեյս է օգտագործում կոնկրետ օբյեկտների ստեղծման համար, որոնք որ հանդիսանում են թեմայի մաս։ Հայցողը (անգլ.՝ client) չգիտե, թե ինչ կոնկրետ օբյեկտներ է ստանում ամեն մի ներքին ֆաբրիկայից, քանի որ նա իր ապրանքները (անգլ.՝ products) ստեղծելու համար օգտագործում է ընդհանուր ինտերֆեյս[2]։ Մոդելն առանձնացնում է իրականացման մանրամասները օբյեկտների բազմությունից և հիմնվում է օբյեկտի կոմպոզիցիայի վրա, որտեղ օբյեկտի ստեղծումը իրականացվում է ֆաբրիկայի ինտերֆեյսի մեթոդներով[3]։

Աբստրակտ ֆաբրիկա
ՏեսակՍտեղծող
ՆշանակությունՏրամադրում է ինտերֆեյս փոխկապակցված օբյեկտների ստեղծման համար` առանց նշելու կոնկրետ դասը։
Կառուցվածք
ԿիրառությունՀետևյալն է.
  • Երբ ծրագիրը պետք է անկախ լինի պրոցեսից և նորաստեղծ օբյեկտների տեսակից
  • Երբ անհրաժեշտ է ստեղծվել կապակցված օբյեկտների խումբ բացառելով միևնույն կոնտեքստում տարբեր հավաքածուի օգտագործումը[1]։.
ԱռավելություններՀետևյալն է.
  • տարբեր դասեր մեկուսացնում է իրարից,
  • հեշտացնում է ապրանքի ընտանիքների փախարինումը,
  • երաշխավորում է ապրանքների համատեղելիությունը։
ԹերություններԴժվար է ավելացնել նոր տիպի ապրանքի սպասարկում։
Նկարագրությունը ԳօՖի
"Design Patterns" գրքում
Այո

Որպես Աբստրակտ ֆաբրիկայի նմւոշ կարող է հանդիսանալ DocumentCreator դասը, որն ինտերֆեյսներ է ապահովում մի շարք արգասիքներ (անգլ.՝ product) (օրինակ createLetter() և createResume()) ստեղծելու համար։ Այս համակարգը կունենա ցանակացած քանակության DocumentCreator դասերի տարբերակներ, որպիսիք են FancyDocumentCreator կամ ModernDocumentCreator, որոնցից ամեն մեկն ունի createLetter() և createResume() իրականացումներ, որպեսզի ստեղծի համապատասխանաբար FancyLetter կամ ModernResume օբյեկտներ։ Այս արգասիքներից յուրաքանչյուրն հանդիսանում է պարզ աբստրակտ Letter կամ Resume դասերի տեսքով, որոնց ճանաչում է հայցողը (անգլ.՝ client)։ Հայցողի կոդը կստանա DocumentCreator-ի համապատասխան օրինակ և կկանչի իր ֆաբրիկային մեթոդը։ Բոլոր ստացված օբյեկտները կիրականացվեն միևնույն DocumentCreator-ի միջոցով։ Հայցողը միայն պետք է իմանա, թե ինչպես պետք է դիմել Letter կամ Resume աբստրակտ դասերին, այլ ոչ թե ֆաբրիկային մեթոդի հատուկ տարբերակի կանչը։

Ֆաբրիկան հանդիսանում է կոնկրետ դաս ծրագրավորման կոդի մեջ, որի միջոցով ստեղծվում է օբյեկտները։ Այս նախագծման ձևանմուշի օգտագործման նպատակահարմարությունը նրանումն է, որ առանձնացնվի օբյեկտի ստեղծումը նրա օգտագործումից կամ էլ կապակցված օբյեկտների ընտանիքի ստեղծումը, որոնք կախված չեն կոնկրետ դասերից[3]։ Դա թույլ է տալիս նոր կամայական տիպ ներմուծել կոդի մեջ առանց բազային կոդը փոփոխման ենթարկելու։

Այս ձևանմուշի օգտագործումը թույլ է տալիս տեղերով փոփոխել կոնկրետ իրականացումները առանց դրանք կանչվող կոդի փոփոխության, անգամ ծրագրի իրականացման պահին։ Այնուամենայնիվ, այս ձևանմուշի, ինչպես նաև նմանատիպ այլ նախագծման մոդելներների օգտագործումը կարող է դառնալ ավելորդ բարդության և լրացուցիչ աշխատանքի պատճառ սկզբանական կոդը կազմելիս։ Բացի այդ կոդի բարձր մակարդակի բաժանումը և աբստրակցիան կարող են համակարգը դարձնել դժվար սպասարկվող և թեսթավորվող։ Դրա համար էլ նախքան այն կիրառելը բոլոր թեր և դեմ կողմերը պետք է լրջորեն ուսումնասիրել։

Ընդհանուր հասկացողություններ խմբագրել

  • Client - հայցող
  • Instance - նմուշ
  • Implementation - իրականացում
  • Product - արգասիք

Նկարագրություն խմբագրել

Աբստրակտ ֆաբրիկա նախագծման ձևանմուշն ինտերֆեյս է ապահովում կապակցված ընտանիքների կամ փոխկապակցված օբյեկտների ստեղծման համար՝ առանց մատնանշելու նրանց կոնկրետ դասերը[4]

Օգտագործումը խմբագրել

Ֆաբրիկան միայն որոշում է թե ինչ կոնկրետ տիպի օբյեկտ պետք է ստեղծվի և որտեղից օբյեկտը իրականում պետք է ստեղծվի (օրինակ C++ լեզվում new օպերատորի) կիրառմամբ։ Այնուամենայնիվ, ֆաբրիկան միայն աբստրակտ ցուցիչ է վերադարձնում ստեղծված կոնկրետ օբյեկտի վրա։

Այս մեխանիզմը մեկուսացնում է հայցողի կոդը օբյեկտի ստեղծումից։ Հայցողը ֆաբրիկայից ցանկալի տիպի օբյեկտ է կանչում և ստանում է աբստրակտ ցուցիչ այդ օբյեկտի վրա[5]։

Քանի որ ֆաբրիկան վերադարձնում է միայն աբստրակտ ցուցիչ, հայցողի կոդը (որ ֆաբրիկայից օբյեկտ է հայցել) չգիտե, թե այդ պահին կոնկրետ ինչ օբյեկտ ստեղծվեց։ Այնուամենայնիվ, կոնկրետ օբյեկտի տիպը (և, հետևաբար, կոնկրետ ֆաբրիկան) հանդիսանում է որպես աբստրակտ ֆաբրիկայի նմուշ (անգլ.՝ instance)։ Ֆաբրիկան այն կարող է կարդալ կոնկրետ կոնֆիգուրացիոն ֆայլից։ Մասնավորապես դա նշանակում է.

  • Հայցողի կոդը ընդհանրապես կախված չէ կոնկրետ տիպից և կարիք չկա այնտեղ ներառել որևէ header file կամ էլ դաս հայտարարել։ Հայցողի կոդը գործ ունի միայն աբստրակտ տիպի հետ։ Կոնկրետ տիպի օբյեկտները իրականում ստեղծվում են ֆաբրիկայում, բայց հայցողի կոդին օբյեկտները հասանելի է միայն նրանց աբստրակտ ինտերֆեյսի միջոցով[6]։
  • Նոր կոնկրետ տիպերի ավելացումն արվում է հայցողի կոդի փոփոխմամբ՝ օգտագործելով այլ ֆաբրիկա։ Տարբեր ֆաբրիկաներ ստեղծում են տարբեր տիպերի կոնկրետ օբյեկտներ, բայց նախկինի պես վերադարձնում են նույն տիպի աբստրակտ ցուցիչ՝ մեկուսացնելով հայցողի կոդը փոփոխություններից։ Սա ավելի հեշտ է, քան հայցողի կոդի փոփոխումը, որպեսզի ստեղծվի նոր տիպի օբյեկտ, որը կպահանջեր փոփոխություններ կատարել կոդի բոլոր մասերում, որտեղ որ ստեղծվում է նոր օբյեկտը (ինչպես նաև համոզվել, որ կոդի այդ մասերում բավարար ինֆորմացիա կա նոր կոնկրետ տիպի մասին՝ ներառելով դասի header ֆայլը)։ Եթե ֆաբրիկայի օբյեկտները պահվում են որպես գլոբալ միայնակ օբյեկտ և հայցողի կոդը մի անգամ է կանչում տվյալ ֆաբրիկային օբյեկտ ստեղծելու համար, ապա ֆաբրիկայի օբյեկտի փոփոխումը նույնքան հեշտ է, որքան որ միայնակ օբյեկտի փոփոխումը[6]։

Կառուցվածք խմբագրել

Խելացի դասի սխեմա խմբագրել

 

GuiFactory ինտերֆեյսի createButton մեթոդը վերադարձնում է Button տիպի օբյեկտը։ Button օբյեկտի վերադարձի իրականացումը կախված է GuiFactory-ի կանչի մեթոդից։

UML դասի սխեմա խմբագրել

 

Պսեվդոկոդ խմբագրել

Կախված թե ինչ ֆաբրիկա է օգտագործվում, պետք է պատկերել կոճակը կամ Windows կամ էլ Mac OS X ոճով։ Ուշադրություն դարձրեք, որ ծրագիրը գաղափար անգամ չունի, թե ինչ GUIFactory է կանչվում կոճակը ստեղծելու ժամանակ։

interface Button is
 method paint()

interface GUIFactory is
 method createButton()
   output:  a button

class WinFactory implementing GUIFactory is
 method createButton() is
   output:  a Windows button
  Return a new WinButton

class OSXFactory implementing GUIFactory is
 method createButton() is
   output:  an OS X button
  Return a new OSXButton

class WinButton implementing Button is
 method paint() is
  Render a button in a Windows style

class OSXButton implementing Button is
 method paint() is
  Render a button in a Mac OS X style

class Application is
 constructor Application(factory) is
   input:  the GUIFactory factory used to create buttons
  Button button := factory.createButton()
  button.paint()

Read the configuration file
If the OS specified in the configuration file is Windows, then
 Construct a WinFactory
 Construct an Application with WinFactory
else
 Construct an OSXFactory
 Construct an Application with OSXFactory

Օրինակներ խմբագրել

C# խմբագրել

Աբստրակտ ֆաբրիկան բազային Ֆաբրիկա մոդելի ընդլայնումն է։ Այն ապահովում է Ֆաբրիկա ինտերֆեյսներ փոխկապակցված դասերի ընտանիք ստեղծելու համար։

/*IVSR:Abstract factory pattern*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace DesignPatterns.AbstractFactory
{
    public class GenericFactory<T> 
        where T : new()
    {
        public T CreateObject()
        {
            return new T();
        }
    }

    public abstract class CarFactory
    {
        public abstract SportsCar CreateSportsCar();
        public abstract FamilyCar CreateFamilyCar();
    }
    
    public abstract class FamilyCar
    {
        public abstract void Speed(SportsCar abstractFamilyCar);
    }

    public abstract class SportsCar
    {
    }

    public class MercedesFactory : CarFactory
    {
        public override SportsCar CreateSportsCar()
        {
            return new MercedesSportsCar();
        }

        public override FamilyCar CreateFamilyCar()
        {
            return new MercedesFamilyCar();
        }
    }
    
    
    class MercedesSportsCar : SportsCar
    {
    }

    class MercedesFamilyCar : FamilyCar
    {
        public override void Speed(SportsCar abstractSportsCar)
        {
            Console.WriteLine(GetType().Name + " is slower than "
                + abstractSportsCar.GetType().Name);
        }
    }

    public class Driver
    {
        private CarFactory _carFactory;
        private SportsCar _sportsCar;
        private FamilyCar _familyCar;

        public Driver(CarFactory carFactory)
        {
            CarFactory = carFactory;
            SportsCar = CarFactory.CreateSportsCar();
            FamilyCar = CarFactory.CreateFamilyCar();
        }

        private CarFactory CarFactory
        {
            get { return _carFactory; }
            set { _carFactory = value; }
        }

        private SportsCar SportsCar
        {
            get { return _sportsCar; }
            set { _sportsCar = value; }
        }

        private FamilyCar FamilyCar
        {
            get { return _familyCar; }
            set { _familyCar = value; }
        }

        public void CompareSpeed()
        {
            FamilyCar.Speed(SportsCar);
        }
    }
}

Ֆաբրիկային մեթոդը նույնպես իրականացված է ընդհանուր ինտերֆեյսից օգտվելով, և նրանցից յուրաքանչյուրը վերադարձնում է օբյեկտներ։

//IVSR: Abstract factory using common interface
public interface IFactory1
    {
        IPeople GetPeople();
    }
    public class Factory1 : IFactory1
    {
        public IPeople GetPeople()
        {
            return new Villagers();
        }
    }

    public interface IFactory2
    {
        IProduct GetProduct();
    }
    public class Factory2 : IFactory2
    {
        public IProduct GetProduct()
        {
            return new IPhone();
        }
    }

    public abstract class AbstractFactory12
    {
        public abstract IFactory1 GetFactory1();
        public abstract IFactory2 GetFactory2();
    }

    public class ConcreteFactory : AbstractFactory12
    {

        public override IFactory1 GetFactory1()
        {
            return new Factory1();
        }

        public override IFactory2 GetFactory2()
        {
            return new Factory2();
        }
    }

Ծանոթագրություններ խմբագրել

  1. «Паттерн Abstract Factory». Արխիվացված օրիգինալից 2013 թ․ հունիսի 14-ին. Վերցված է 2013 թ․ հունիսի 14-ին.
  2. 2,0 2,1 Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike (eds.). «Head First Design Patterns» (paperback). 1. O'REILLY: 156. ISBN 978-0-596-00712-6. Վերցված է 2012 թ․ սեպտեմբերի 12-ին. {{cite journal}}: Cite journal requires |journal= (օգնություն)
  3. 3,0 3,1 Freeman, Eric; Freeman, Elisabeth; Kathy, Sierra; Bert, Bates (2004). Hendrickson, Mike; Loukides, Mike (eds.). «Head First Design Patterns» (paperback). 1. O'REILLY: 162. ISBN 978-0-596-00712-6. Վերցված է 2012 թ․ սեպտեմբերի 12-ին. {{cite journal}}: Cite journal requires |journal= (օգնություն)
  4. Gamma, Erich; Richard Helm; Ralph Johnson; John M. Vlissides (2009 թ․ հոկտեմբերի 23). «Design Patterns: Abstract Factory». informIT. Արխիվացված է օրիգինալից 2012 թ․ մայիսի 16-ին. Վերցված է 2012 թ․ մայիսի 16-ին. «Object Creational: Abstract Factory: Intent: Provide an interface for creating families of related or dependent objects without specifying their concrete classes.»
  5. Veeneman, David (2009 թ․ հոկտեմբերի 23). «Object Design for the Perplexed». The Code Project. Արխիվացված է օրիգինալից 2011 թ․ փետրվարի 21-ին. Վերցված է 2012 թ․ մայիսի 16-ին. «The factory insulates the client from changes to the product or how it is created, and it can provide this insulation across objects derived from very different abstract interfaces.»
  6. 6,0 6,1 «Abstract Factory: Implementation». OODesign.com. Վերցված է 2012 թ․ մայիսի 16-ին.

Արտաքին հղումներ խմբագրել