Salom! Bugun biz dizayn naqshlarini o'rganishni davom ettiramiz va zavod usuli (FactoryMethod) haqida gapiramiz. Bu nima ekanligini va ushbu shablon qanday vazifalarga mos kelishini bilib olasiz. Biz ushbu dizayn naqshini amalda ko'rib chiqamiz va uning tuzilishini o'rganamiz. Yuqoridagilarning barchasi sizga tushunarli bo'lishi uchun siz quyidagi mavzularni tushunishingiz kerak:
- Java-da meros.
- Java tilidagi abstrakt usullar va sinflar.
Zavod usuli qanday muammoni hal qiladi?
Barcha zavod dizayn namunalarida ishtirokchilarning ikki guruhi mavjud - yaratuvchilar (zavodlarning o'zlari) va mahsulotlar (zavodlar tomonidan yaratilgan ob'ektlar). Vaziyatni tasavvur qiling: bizda AutoRush brendi ostida avtomobillar ishlab chiqaradigan zavod bor. U har xil turdagi korpuslarga ega avtomobil modellarini qanday yaratishni biladi:- sedanlar
- stansiya vagonlari
- kupe
- AutoRush sedanlari
- AutoRush stantsiya vagonlari
- kupe AutoRush
- OneAuto sedanlari
- OneAuto stantsiya vagonlari
- OneAuto kupe
Zavod shablonlari haqida bir oz
Sizga eslatib o'taman: biz siz bilan kichik virtual qahvaxona qurdik. Unda biz oddiy zavod yordamida turli xil qahva turlarini yaratishni o'rgandik. Bugun biz ushbu misolni aniqlaymiz. Keling, oddiy zavodga ega qahvaxonamiz qanday ko'rinishga ega bo'lganini eslaylik. Bizda kofe darsi bor edi:public class Coffee {
public void grindCoffee(){
// перемалываем кофе
}
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
Shuningdek, uning bir qancha merosxo'rlari - fabrikamiz ishlab chiqarishi mumkin bo'lgan kofe turlari:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Buyurtmalarni qabul qilish qulayligi uchun biz o'tkazmalarni joriy qildik:
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
Qahva fabrikasining o'zi shunday ko'rinardi:
public class SimpleCoffeeFactory {
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new Americano();
break;
case ESPRESSO:
coffee = new Espresso();
break;
case CAPPUCCINO:
coffee = new Cappuccino();
break;
case CAFFE_LATTE:
coffee = new CaffeLatte();
break;
}
return coffee;
}
}
Va nihoyat, qahvaxonaning o'zi:
public class CoffeeShop {
private final SimpleCoffeeFactory coffeeFactory;
public CoffeeShop(SimpleCoffeeFactory coffeeFactory) {
this.coffeeFactory = coffeeFactory;
}
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
}
Oddiy zavodni modernizatsiya qilish
Bizning qahvaxonamiz yaxshi ishlaydi. Shu qadar ko'pki, biz kengaytirish haqida o'ylayapmiz. Biz bir nechta yangi nuqtalarni ochmoqchimiz. Tashabbuskor yigitlar sifatida biz monoton qahvaxonalarni yo'qotmaymiz. Men har birining o'ziga xos burilish bo'lishini xohlayman. Shuning uchun, boshlash uchun biz ikkita nuqta ochamiz: italyan va amerikacha uslublarda. O'zgarishlar nafaqat ichki makonga, balki ichimliklarga ham ta'sir qiladi:- italyan qahvaxonasida biz maxsus maydalash va qovurish bilan faqat italyan kofe brendlaridan foydalanamiz.
- Amerika qismi biroz kattaroq bo'ladi va har bir buyurtma bilan biz eritilgan marshmallowlar - marshmallowlarni taqdim etamiz.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Va u 8 ga aylanadi:
public class ItalianStyleAmericano extends Coffee {}
public class ItalianStyleCappucino extends Coffee {}
public class ItalianStyleCaffeLatte extends Coffee {}
public class ItalianStyleEspresso extends Coffee {}
public class AmericanStyleAmericano extends Coffee {}
public class AmericanStyleCappucino extends Coffee {}
public class AmericanStyleCaffeLatte extends Coffee {}
public class AmericanStyleEspresso extends Coffee {}
Biz joriy biznes modelini o'zgarmagan holda saqlashni xohlayotganimiz sababli, usul orderCoffee(CoffeeType type)
minimal miqdordagi o'zgarishlarga duchor bo'lishini xohlaymiz. Keling, buni ko'rib chiqaylik:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
Bizda qanday variantlar bor? Biz zavodni qanday yozishni allaqachon bilamiz, to'g'rimi? Darhol aqlga keladigan eng oddiy narsa - ikkita o'xshash zavodni yozish va keyin kerakli dasturni konstruktordagi qahvaxonamizga o'tkazish. Shunda qahvaxonaning sinfi o'zgarmaydi. Birinchidan, biz yangi zavod sinfini yaratishimiz, oddiy zavodimizdan meros olishimiz va createCoffee (CoffeeType type)
. Keling, italyan va amerikacha uslubda qahva yaratish uchun fabrikalarni yozaylik:
public class SimpleItalianCoffeeFactory extends SimpleCoffeeFactory {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
public class SimpleAmericanCoffeeFactory extends SimpleCoffeeFactory{
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
Endi biz CoffeeShop-ga kerakli zavodni amalga oshirishimiz mumkin. Keling, turli xil qahvaxonalardan kofe buyurtma qilish uchun kod qanday ko'rinishini ko'rib chiqaylik. Masalan, italyan va amerikacha uslubdagi kapuchino:
public class Main {
public static void main(String[] args) {
/*
Закажем капучино в итальянском стиле:
1. Создадим фабрику для приготовления итальянского кофе
2. Создадим новую кофейню, передав ей в конструкторе фабрику итальянского кофе
3. Закажем наш кофе
*/
SimpleItalianCoffeeFactory italianCoffeeFactory = new SimpleItalianCoffeeFactory();
CoffeeShop italianCoffeeShop = new CoffeeShop(italianCoffeeFactory);
italianCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
/*
Закажем капучино в американском стиле
1. Создадим фабрику для приготовления американского кофе
2. Создадим новую кофейню, передав ей в конструкторе фабрику американского кофе
3. Закажем наш кофе
*/
SimpleAmericanCoffeeFactory americanCoffeeFactory = new SimpleAmericanCoffeeFactory();
CoffeeShop americanCoffeeShop = new CoffeeShop(americanCoffeeFactory);
americanCoffeeShop.orderCoffee(CoffeeType.CAPPUCCINO);
}
}
Biz ikkita turli qahvaxona yaratdik, har birini kerakli zavodga o'tkazdik. Bir tomondan maqsadimizga erishdik, bir tomondan... Nimadir tadbirkorning tinimsiz ruhini tirnayapti... Keling, nima bo‘lganini aniqlaylik. Birinchidan, zavodlarning ko'pligi. Har safar yangi nuqta uchun o'z zavodingizni yaratish va qo'shimcha ravishda qahvaxonani yaratishda kerakli zavod konstruktorga o'tkazilishiga ishonch hosil qilish mumkinmi? Ikkinchidan, u hali ham oddiy zavod. Bir oz modernizatsiya qilingan. Biz bu erda hali ham yangi naqshni o'rganmoqdamiz. Uchinchidan, buni boshqacha qilish mumkin emasmi? Agar biz sinfda qahva tayyorlash bo'yicha barcha savollarni lokalizatsiya qilsak CoffeeShop
, qahva yaratish va buyurtmaga xizmat ko'rsatish jarayonlarini bog'lab olsak, yaxshi bo'lar edi, lekin ayni paytda turli xil uslublarda qahva tayyorlash uchun etarlicha moslashuvchanlikni saqlasak. Javob ha, mumkin. Bu zavod usuli dizayn namunasi deb ataladi.
Oddiy zavoddan zavod usuliga
Muammoni iloji boricha samarali hal qilish uchun biz:- Keling, usulni
createCoffee(CoffeeType type)
sinfga qaytaraylikCoffeeShop
. - Keling, bu usulni mavhum qilaylik.
- Sinfning o'zi
CoffeeShop
mavhum bo'ladi. - Sinfning
CoffeeShop
merosxo'rlari bo'ladi.
CoffeeShop
uslubni amalga oshiradigan sinfning merosxo'ridan boshqa narsa emas . createCoffee(CoffeeType type)
Shunday qilib, tartibda. 1-qadam. Keling, sinfni Coffee
abstrakt qilaylik. Hozir bizda turli xil mahsulotlarning ikkita oilasi bor. Italiya va Amerika kofe ichimliklar hali ham umumiy ajdodga ega: Coffee
. Buni mavhum qilish to'g'ri bo'ladi:
public abstract class Coffee {
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
CoffeeShop
Qadam 2. Mavhum usul bilan mavhum qilingcreateCoffee(CoffeeType type)
public abstract class CoffeeShop {
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = createCoffee(type);
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
protected abstract Coffee createCoffee(CoffeeType type);
}
Qadam 3. Mavhum qahvaxonaning avlodi bo'lgan italyan qahvaxonasini yarating. Unda biz createCoffee(CoffeeType type)
italyan o'ziga xosligini hisobga olgan holda usulni amalga oshiramiz.
public class ItalianCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new ItalianStyleAmericano();
break;
case ESPRESSO:
coffee = new ItalianStyleEspresso();
break;
case CAPPUCCINO:
coffee = new ItalianStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new ItalianStyleCaffeLatte();
break;
}
return coffee;
}
}
Qadam 4. Amerika uslubidagi qahvaxona uchun ham xuddi shunday qilaylik.
public class AmericanCoffeeShop extends CoffeeShop {
@Override
public Coffee createCoffee (CoffeeType type) {
Coffee coffee = null;
switch (type) {
case AMERICANO:
coffee = new AmericanStyleAmericano();
break;
case ESPRESSO:
coffee = new AmericanStyleEspresso();
break;
case CAPPUCCINO:
coffee = new AmericanStyleCappuccino();
break;
case CAFFE_LATTE:
coffee = new AmericanStyleCaffeLatte();
break;
}
return coffee;
}
}
5-qadam. Amerika va italyancha uslubdagi lattega buyurtma berish qanday bo'lishini ko'rib chiqamiz:
public class Main {
public static void main(String[] args) {
CoffeeShop italianCoffeeShop = new ItalianCoffeeShop();
italianCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
CoffeeShop americanCoffeeShop = new AmericanCoffeeShop();
americanCoffeeShop.orderCoffee(CoffeeType.CAFFE_LATTE);
}
}
Seni tabriklayman. Biz qahvaxonamizda zavod uslubidagi dizayn namunasini joriy qildik.
Zavod usuli qanday ishlaydi
Endi biz nimani olganimizni batafsil ko'rib chiqaylik. Quyidagi diagrammada olingan sinflar ko'rsatilgan. Yashil bloklar yaratuvchi sinflari, ko'k bloklar mahsulot sinflari. Qanday xulosalar chiqarish mumkin?- Barcha mahsulotlar mavhum sinfning amalga oshirilishidir
Coffee
. - Barcha yaratuvchilar mavhum sinfning amalga oshirilishidir
CoffeeShop
. - Biz ikkita parallel sinf ierarxiyasini kuzatamiz:
- Mahsulotlar ierarxiyasi. Biz Italiya avlodlarini va Amerika avlodlarini ko'ramiz
- Ijodkorlar ierarxiyasi. Biz Italiya avlodlarini va Amerika avlodlarini ko'ramiz
- Superklassda qaysi maxsus mahsulotning amalga oshirilishi ( ) yaratilishi
CoffeeShop
haqida hech qanday ma'lumot yo'q .Coffee
- Superklass
CoffeeShop
ma'lum bir mahsulotni yaratishni o'z avlodlariga topshiradi. - Har bir avlod sinfi o'ziga xos xususiyatlarga muvofiq
CoffeeShop
zavod usulini amalga oshiradi .createCoffee()
Boshqacha qilib aytganda, ijodkorlar sinflarini amalga oshirish doirasida yaratuvchilar sinfining o'ziga xos xususiyatlaridan kelib chiqqan holda ma'lum bir mahsulotni tayyorlash to'g'risida qaror qabul qilinadi.
Zavod usuli tuzilishi
Yuqoridagi diagrammada zavod usuli naqshining umumiy tuzilishi ko'rsatilgan. Bu erda yana nima muhim?- Creator klassi zavod usulidan tashqari mahsulotlar bilan o'zaro ta'sir qiluvchi barcha usullarni amalga oshirishni o'z ichiga oladi.
- Mavhum usul
factoryMethod()
sinfning barcha avlodlari tomonidan amalga oshirilishi kerakCreator
. - Sinf mahsulotni bevosita ishlab chiqaradigan
ConcreteCreator
usulni amalga oshiradi .factoryMethod()
- Bu sinf ma'lum mahsulotlarni yaratish uchun javobgardir. Bu ushbu mahsulotlarni yaratish haqida ma'lumotga ega bo'lgan yagona sinf.
- Barcha mahsulotlar umumiy interfeysni amalga oshirishi kerak - umumiy mahsulot sinfining avlodlari bo'lishi kerak. Bu mahsulotlardan foydalanadigan sinflar ular ustida aniq amalga oshirish emas, balki abstraktsiyalar darajasida ishlashi uchun zarurdir.
GO TO FULL VERSION