Кіріспе
Басқа объектілерді жасайтын объект. Объектіге бағытталған бағдарламалауда фабрика – басқа объектілерді құруға арналған объект; формальды түрде, ол "жаңа" деп есептелетін әдіс шақыруларынан әртүрлі прототиптің немесе кластың объектілерін қайтаратын функция немесе әдіс. Көбірек мағынада, "жаңа" объектіні қайтаратын кез келген процедураны "фабрика" деп атауға болады, мысалы, фабрика әдісі немесе фабрика функциясы. Фабрика үлгісі – көптеген бағдарламалық жасақтаманы жобалау үлгілерінің негізі.
In object oriented programming, a factory is an object for creating other objects; formally, it is a function or method that returns objects of a varying prototype or class from some method call, which is assumed to be "new". More broadly, a subroutine that returns a "new" object may be referred to as a "factory", as in factory method or factory function. The factory pattern is the basis for a number of related software design patterns.
Мотивация
Сыныпқа негізделген бағдарламалауда фабрика – кластың конструкторының абстракциясы, ал прототипке негізделген бағдарламалауда фабрика – прототип объектісінің абстракциясы. Конструктор нақты, себебі ол объектілерді бір ғана кластың мысалы ретінде және белгілі бір процесс (кластың құрылуы) арқылы жасайды, ал фабрика әртүрлі кластарды құру арқылы немесе объектілер жиыны сияқты басқа бөлу схемаларын пайдалану арқылы объектілерді құра алады. Прототип объектісі нақты, себебі ол клондау арқылы объектілерді құру үшін қолданылады, ал фабрика әртүрлі прототиптерді клондау арқылы немесе басқа бөлу схемалары арқылы объектілерді құра алады. Фабриканы әртүрлі тәсілдермен іске асыруға болады. Көбінесе ол әдіс ретінде іске асырылады, онда ол фабрикалық әдіс деп аталады. Кейде ол функция ретінде іске асырылады, онда ол фабрикалық функция деп аталады. Кейбір тілдерде конструкторлардың өзі фабрика болып табылады. Дегенмен, көптеген тілдерде олар фабрика емес, конструкторлар тілге тән ерекшеліктермен шақырылады, мысалы, `new` кілт сөзін пайдалану арқылы, ал фабриканың ерекше мәртебесі жоқ және ол әдеттегі әдіс немесе функция арқылы шақырылады. Осы тілдерде фабрика конструктордың абстракциясы болып табылады, бірақ қатаң айтқанда, жалпылама емес, өйткені конструкторлар өздері фабрика емес.
Терминология
Терминология зауыт ұғымының өзі дизайн үлгісі болып табылатынына қатысты әртүрлі. "Дизайн үлгілерінде" "зауыт үлгісі" деген атау жоқ, бірақ оның орнына зауыттарды пайдаланатын екі үлгі бар (зауыт әдісі үлгісі және абстрактілі зауыт үлгісі). Кейбір дереккөздер бұл ұғымды зауыт үлгісі деп атайды, ал басқалары ұғымның өзін бағдарламалау тәсілі (идиомасы) деп санайды, "зауыт үлгісі" немесе "зауыт үлгілері" терминін зауыттарды қолданатын, көбінесе зауыт әдісі үлгісі сияқты күрделі үлгілерге арнайды; осы ретте, зауыттың өзі туралы түсінік қарапайым зауыт деп аталуы мүмкін. "Зауыт" деген сөзді кең мағынада, тек әлдебір әдіс шақыру арқылы объектілерді қайтаратын объектіге ғана емес, сонымен қатар фабрика функциясы (функциялар объектілер болмаса да) немесе фабрика әдісі сияқты объектілерді қайтаратын процедураға да қолдануға болады. Көптеген тілдерде зауыттар әдіс шақыру арқылы іске қосылатындықтан, зауыттың жалпы түсінігі жиі нақты зауыт әдісі үлгісін жобалау үлгісімен шатастырылады.
Нысанды құру
Зауыттық объектілер белгілі бір түрдегі объектіні алу, жаңа объектіні құрудан гөрі күрделі процесс болатын жағдайларда қолданылады, әсіресе күрделі бөлу немесе бастамалау қажет болғанда. Объектіні құруға қажетті процестердің кейбіреулеріне, қандай объектіні құруды анықтау, объектінің өмір сүру мерзімін басқару және объектінің ерекше құрастыру мен жою мәселелерін басқару кіреді. Зауыттық объекті объектінің класын (болған жағдайда) динамикалық түрде құруға, оны объектілер жиынынан қайтаруға, объектіде күрделі конфигурация жасауға немесе басқа да шаралар қолдануға шешім қабылдауы мүмкін. Сол сияқты, осы анықтамаға сәйкес, синглтон үлгісі арқылы іске асырылған синглтон – бұл ресми зауыт, ол объектіні қайтарады, бірақ жалғыз данадан басқа жаңа объектілерді жасамайды.
Синтаксисі
Фабрикалар әр түрлі жолдармен қолданылуы мүмкін, көбінесе әдіс шақыру арқылы (фабрика әдісі), кейде фабрика шақырылатын объект болса, функция ретінде шақырылады (фабрика функциясы). Кейбір тілдерде конструкторлар мен фабрикалардың синтаксисі бірдей, ал басқаларында конструкторлардың ерекше синтаксисі бар. Конструкторлар мен фабрикалардың синтаксисі бірдей болатын тілдерде, мысалы Python, Perl, Ruby, Object Pascal және F#, конструкторларды фабрикалармен көзге көрінбей ауыстыруға болады. Егер олар әр түрлі болса, интерфейстерде оларды ажырату қажет, ал конструкторлар мен фабрикалардың арасында ауысу шақыруларды өзгертуді талап етеді.
Семантика
Динамикалық түрде жадқа бөлінетін тілдерде, мысалы Java немесе Python, фабрикалар мағынасы жағынан конструкторлармен бірдей. Дегенмен, C++ сияқты кейбір нысандарды статикалық түрде жадқа бөлуге рұқсат беретін тілдерде, фабрикалар статикалық жадқа бөлінген сыныптар үшін конструкторлардан өзгеше. Себебі, соңғыларының жадқа бөлінуі компиляция кезінде анықталуы мүмкін, ал фабрикалар қайтаратын мәндердің жадқа бөлінуі орындалу кезінде анықталуы тиіс. Егер конструкторды функцияға аргумент ретінде жіберуге болады, онда конструкторды шақыру және қайтарылатын мәнді жадқа бөлу орындалу уақытында динамикалық түрде жүзеге асырылуы керек, демек фабриканы шақырумен ұқсас немесе толықтай бірдей мағынаға ие болуы керек.
Құрылыс үлгілері
Зауыттар түрлі дизайн үлгілерінде қолданылады, әсіресе шығармашылық үлгілерде, мысалы, дизайн үлгісі объектілерінің кітапханасында. Көптеген тілдерде оларды іске асыру үшін арнайы әдістер әзірленген. Мысалы, "Factory method pattern", "Builder" немесе тіпті "Singleton" сияқты бірнеше "GoF үлгілері" осы ұғымның іске асырылуы болып табылады. "Абстрактілі фабрика үлгісі" фабрикалар жинағын құру тәсілі болып табылады. Кейбір дизайн үлгілерінде фабрика объектісі өзі құра алатын әрбір объект түрі үшін әдіске ие. Бұл әдістер объектінің қалай құрылатынын анықтайтын параметрлерді қабылдауы мүмкін, содан кейін құрылған объектіні қайтарады.
Қолданбалар
Фабрика объектілері құралдар жиынтығында және фреймворктерде кеңінен қолданылады, онда кітапхана коды фреймворкты пайдаланатын қосымшалармен кеңейтілген типтердің объектілерін жасауы керек. Олар тесттік дамытуда сыныптарды сынауға мүмкіндік беру үшін де пайдаланылады. Фабрикалар жасалатын нақты объектінің типін анықтайды және объектінің жасалуы осы жерде жүзеге асырылады. Фабрика объектіге тек абстрактілі интерфейсті қайтаратындықтан, клиенттік код объектінің нақты типін білмейді және осы ақпаратмен жүктелмейді. Дегенмен, нақты объектінің типі абстрактілі фабрикаға белгілі. Атап айтқанда, бұл мынаны білдіреді:
Клиенттік код нақты тип туралы ешқандай ақпаратқа ие емес, сондықтан нақты типке қатысты ешқандай бас файлдарды немесе сынып жарияланымдарын қосудың қажеті жоқ. Клиенттік код тек абстрактілі типпен ғана жұмыс істейді. Нақты типтегі объектілер шынымен де фабрикада жасалады, бірақ клиенттік код осы объектілерге тек абстрактілі интерфейсі арқылы ғана қол жеткізеді. Жаңа нақты типтерді қосу клиенттік кодты басқа фабриканы пайдалану үшін өзгерту арқылы жүзеге асырылады, мұндай өзгеріс әдетте бір файлда бір жолдан тұрады. Бұл клиенттік кодты жаңа типті жасау үшін өзгертуге қарағанда әлдеқайда оңай, себебі сонда кодтың жаңа объекті жасалатын әрбір бөлігін өзгерту қажет болады.
Жеңімпаздық және нұсқалар
Дизайн үлгілерінде қолданылудан өзге, фабрикалар, әсіресе фабрикалық әдістер, түрлі пайдалары мен нұсқаларына ие.
Капсулалау
Зауыттық әдістер нысандарды жасауды қамтиды. Бұл жасау процесі өте күрделі болған жағдайда пайдалы болуы мүмкін; мысалы, егер ол конфигурациялық файлдардағы параметрлерге немесе пайдаланушы енгізген деректерге байланысты болса. Мысалы, сурет файлдарын оқитын бағдарламаны қарастырайық. Бағдарлама әртүрлі кескін форматтарын қолдайды, әр формат үшін оқырман класы арқылы ұсынылады. Бағдарлама әр суретті оқыған сайын, файлдағы белгілі бір ақпаратқа сүйене отырып, тиісті типтегі оқырманды жасауы керек. Бұл логиканы зауыттық әдіс арқылы енгізуге болады. Бұл тәсіл "Жай фабрика" деп те аталады.
Шектеулер
Зауыттық әдісті қолдануда үш шектеу бар. Біріншісі – қолданыстағы кодты қайта құруға қатысты, ал қалған екеуі – класты кеңейтуге қатысты. Бірінші шектеу – қолданыстағы класты зауыттарды пайдалану үшін қайта құру, қолданыстағы клиенттерді бұзады. Мысалы, егер Complex класы стандартты класс болса, онда мынадай кодты қолданатын көптеген клиенттер болуы мүмкін: Complex c = new Complex(1, 0);
Екі түрлі зауыт қажет екенін түсінгеннен кейін, біз класты өзгертеміз (бұрын көрсетілген кодқа). Бірақ конструктор енді жеке болғандықтан, қолданыстағы клиент коды енді компиляцияланбайды. Екінші шектеу – бұл үлгі жеке конструкторды пайдалануға негізделгендіктен, класты кеңейту мүмкін емес. Кез келген туынды класс мұрагерлік конструкторды шақыруы керек, бірақ егер ол конструктор жеке болса, мұны істеуге болмайды. Үшінші шектеу: егер класс кеңейтілсе (мысалы, конструкторды қорғалған етіп жасау арқылы – бұл тәуекелді, бірақ мүмкін), туынды класс барлық зауыт әдістерінің өздігінен қайта жасалынған нұсқасын дәл сол қолтаңбалармен ұсынуы керек. Мысалы, егер StrangeComplex класы Complex класын кеңейтсе, StrangeComplex барлық зауыт әдістерінің өз нұсқасын ұсынбаса, StrangeComplex.FromPolar(1, Math.PI) шақырылымы күтілетін туынды классдың инстанциясын емес, Complex (жоғарғы класс) инстанциясын береді. Кейбір тілдердің рефлексия мүмкіндіктері бұл мәселенің алдын алуға көмектеседі. Барлық үш проблеманы негізгі бағдарламалау тілін өзгерту арқылы зауыттарды бірінші дәрежелі класс мүшелері етіп өзгерту арқылы шешуге болады (сондай-ақ Виртуалды класс қараңыз).