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

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

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

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

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

## Ընդհանուր հասկացողություններ
* Client - հայցող
* Instance - նմուշ
* Implementation - իրականացում
* Product - արգասիք

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

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

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

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

## Կառուցվածք
### Խելացի դասի սխեմա
center
`GuiFactory` ինտերֆեյսի `createButton` մեթոդը վերադարձնում է `Button` տիպի օբյեկտը։ `Button` օբյեկտի վերադարձի իրականացումը կախված է `GuiFactory`-ի կանչի մեթոդից։

### UML դասի սխեմա
center

## Պսեվդոկոդ
Կախված թե ինչ ֆաբրիկա է օգտագործվում, պետք է պատկերել կոճակը կամ 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#
Աբստրակտ ֆաբրիկան բազային Ֆաբրիկա մոդելի ընդլայնումն է։ Այն ապահովում է Ֆաբրիկա ինտերֆեյսներ փոխկապակցված դասերի ընտանիք ստեղծելու համար։


```csharp
/*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);
        }
    }
}
```


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

```csharp
//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();
        }
    }
```


## Ծանոթագրություններ

## Արտաքին հղումներ
* Abstract Factory  UML սխեմա + նկարագրություն

Կատեգորիա:Ծրագրավորում