Салам! Бүгүн биз дизайн үлгүлөрүн изилдөөнү улантабыз жана фабрикалык ыкма (FactoryMethod) жөнүндө сүйлөшөбүз. Бул эмне экенин жана бул шаблон кандай тапшырмаларга ылайыктуу экенин билесиз. Биз бул дизайн үлгүсүн иш жүзүндө карап, анын түзүлүшүн изилдейбиз. Жогоруда айтылгандардын бардыгы сизге түшүнүктүү болушу үчүн, сиз төмөнкү темаларды түшүнүшүңүз керек:
- Javaдагы мурас.
- Java тorндеги абстракттуу методдор жана класстар.
Заводдук ыкма кандай маселени чечет?
Бардык фабрикалык дизайн моделдеринде катышуучулардын эки тобу бар - жаратуучулар (фабрикалардын өздөрү) жана буюмдар (заводдор тарабынан түзүлгөн an objectтер). Кырдаалды элестетип көргүлө: бизде AutoRush маркасы менен машиналарды чыгарган завод бар. Ал дененин ар кандай түрлөрү менен унаа моделдерин жасоону билет:- седандар
- станция вагондору
- купе
- AutoRush седандары
- AutoRush станциясынын вагондору
- купе AutoRush
- OneAuto седандары
- OneAuto станция вагондору
- OneAuto купе
Заводдун шаблону жөнүндө бир аз
Эске сала кетейин: биз сиздер менен чакан виртуалдык кофе дүкөнүн курганбыз. Анда биз жөнөкөй завод аркылуу кофенин ар кандай түрлөрүн жасоону үйрөндүк. Бүгүн биз бул мисалды тактайбыз. Жөнөкөй заводу бар кафебиз кандай болгонун эстейли. Биз кофе классын өткөрдүк:public class Coffee {
public void grindCoffee(){
// перемалываем кофе
}
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
Ошондой эле анын бир нече мураскорлору - биздин фабрика чыгара турган кофенин белгилүү түрлөрү:
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Заказдарды кабыл алуунун ыңгайлуулугу үчүн биз которууларды киргиздик:
public enum CoffeeType {
ESPRESSO,
AMERICANO,
CAFFE_LATTE,
CAPPUCCINO
}
Кофе заводунун өзү мындай көрүндү:
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;
}
}
Акыр-аягы, кофе дүкөнүнүн өзү:
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;
}
}
Жөнөкөй заводду модернизациялоо
Биздин кафе жакшы иштеп жатат. Ошентип, биз кеңейтүү жөнүндө ойлонуп жатабыз. Биз бир нече жаңы пункттарды ачкыбыз келет. Демилгелүү жигиттер катары, биз монотондуу кофе дүкөндөрдү жок кылбайбыз. Мен ар биринин өз бурмалоосу болушун каалайм. Ошондуктан, баштоо үчүн, биз эки пункт ачабыз: италиялык жана америкалык стилде. Өзгөртүүлөр интерьерге гана эмес, ичимдиктерге да таасирин тийгизет:- италиялык кофе дүкөнүндө биз атайын майдалоо жана кууртуу менен италиялык кофе бренддерин колдонобуз.
- Америкалык порция бир аз көбүрөөк болот жана ар бир буйрутма менен биз эриген зефирлерди - зефирлерди беребиз.
public class Americano extends Coffee {}
public class Cappuccino extends Coffee {}
public class CaffeLatte extends Coffee {}
public class Espresso extends Coffee {}
Жана 8 болуп калат:
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 {}
Биз учурдагы бизнес моделин өзгөрүүсүз калтыргыбыз келгендиктен, ыкма orderCoffee(CoffeeType type)
минималдуу өзгөрүүлөргө дуушар болушун каалайбыз. Келгиле, аны карап көрөлү:
public Coffee orderCoffee(CoffeeType type) {
Coffee coffee = coffeeFactory.createCoffee(type);
coffee.grindCoffee();
coffee.makeCoffee();
coffee.pourIntoCup();
System.out.println("Вот ваш кофе! Спасибо, приходите еще!");
return coffee;
}
Бизде кандай варианттар бар? Фабриканы кантип жазууну билебиз, туурабы? Эң жөнөкөй нерсе, ошол замат эки окшош заводду жазып, анан конструктордогу кофе дүкөнүбүзгө керектүү ишке өткөрүп берүү. Анда кафенин классы өзгөрбөйт. Биринчиден, биз жаңы фабрика классын түзүп, жөнөкөй фабрикабыздан мурастап, createCoffee (CoffeeType type)
. Келгиле, италиялык жана америкалык стилде кофе жасоо үчүн фабрикаларды жазалы:
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;
}
}
Эми биз CoffeeShop'ка талап кылынган фабриканы ишке ашыра алабыз. Келгиле, ар кандай кофе дүкөндөрүнөн кофе заказ кылуу codeу кандай болорун карап көрөлү. Мисалы, италиялык жана америкалык стилдеги капучино:
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);
}
}
Биз эки башка кафе түзүп, ар бирин керектүү заводго өткөрүп бердик. Бир чети максатыбызга жеттик, экинчи жагынан... Ишкердин батпай турган жан дүйнөсүн бир нерсе тырмап жатат... Эмне болуп жатканын аныктап көрөлү. Биринчиден, заводдордун көптүгү. Ар бир жолу жаңы пункт үчүн өзүңүздүн фабрикаңызды түзүүгө жана кофекананы түзүүдө талап кылынган фабриканын конструкторго өткөрүлүп берorшине ынануу мүмкүнбү? Экинчиден, ал дагы эле жөнөкөй завод. Бир аз модернизацияланган. Бул жерде дагы эле жаңы үлгүнү изилдеп жатабыз. Үчүнчүдөн, муну башкача жасоо мүмкүн эмеспи? CoffeeShop
Эгерде класстын ичинде кофе жасоо боюнча бардык суроолорду локалдаштыруу , кофе түзүү жана тартипти тейлөө процесстерин байланыштырып, бирок ошол эле учурда ар кандай стилде кофе жасоо үчүн жетиштүү ийкемдүүлүктү сактай алсак сонун болмок . Жооп ооба, мүмкүн. Бул фабрикалык ыкма дизайн үлгүсү деп аталат.
Жөнөкөй заводдон заводдук ыкмага
Маселени мүмкүн болушунча натыйжалуу чечүү үчүн, биз:createCoffee(CoffeeType type)
Методду класска кайтаралыCoffeeShop
.- Бул ыкманы абстракттуу кылалы.
- Класс өзү
CoffeeShop
абстракттуу болуп калат. - Класстын
CoffeeShop
мураскорлору болот.
CoffeeShop
ыкманы ишке ашыруучу класстын мураскеринен башка эч нерсе эмес . createCoffee(CoffeeType type)
Ошентип, тартипте. 1-кадам. Классты абстракттуу кылалы Coffee
. Азыр бизде ар кандай буюмдардын эки үй-бүлөсү бар. Италиялык жана америкалык кофе ичимдиктери дагы эле жалпы ата-бабаны бөлүшөт: Coffee
. Абстракттуу кылып койсо туура болмок:
public abstract class Coffee {
public void makeCoffee(){
// делаем кофе
}
public void pourIntoCup(){
// наливаем в чашку
}
}
CoffeeShop
2-кадам . Абстракттуу ыкма менен аны абстракттуу кылыңызcreateCoffee(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);
}
3-кадам. Абстракттуу кофе дүкөнүнүн урпак классы болгон италиялык кофе дүкөнүн түзүңүз. Анда биз createCoffee(CoffeeType type)
италиялык өзгөчөлүктөрдү эске алуу менен ыкманы ишке ашырабыз.
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;
}
}
4-кадам. Америкалык типтеги кофе дүкөнү үчүн да ушундай кылалы.
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-кадам. Келгиле, америкалык жана италиялык стилдеги латтени заказ кылуу кандай болорун карап көрөлү:
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);
}
}
Сени куттуктайм. Биз жаңы эле кофе дүкөнүбүздө фабрикалык дизайн үлгүсүн ишке киргиздик.
Заводдук ыкма кандай иштейт
Эми биз эмнеге ээ болгонубузду жакшыраак карап көрөлү. Төмөнкү диаграмма натыйжада класстарды көрсөтөт. Жашыл блоктор - жаратуучу класстар, көк блоктор - продукт класстары. Кандай тыянак чыгарууга болот?- Бардык продуктулар абстракттуу класстын ишке ашырылышы болуп саналат
Coffee
. - Бардык жаратуучулар абстракттуу класстын ишке ашырылышы болуп саналат
CoffeeShop
. - Биз эки параллелдүү класс иерархиясын байкайбыз:
- Продукциялардын иерархиясы. Биз италиялык урпактарды жана америкалык урпактарды көрөбүз
- Жаратуучулардын иерархиясы. Биз италиялык урпактарды жана америкалык урпактарды көрөбүз
- Суперкласста
CoffeeShop
кайсы продукттун ишке ашырылышы (Coffee
) түзүлө тургандыгы тууралуу маалымат жок. - Суперкласс
CoffeeShop
белгилүү бир буюмду жасоону анын урпактарына өткөрүп берет. - Ар бир тукум класс өзүнүн өзгөчөлүгүнө ылайык
CoffeeShop
заводдук ыкманы ишке ашырат .createCoffee()
Башкача айтканда, жаратуучу класстарды ишке ашыруунун алкагында, жаратуучу класстын өзгөчөлүктөрүнүн негизинде белгилүү бир продуктуну даярдоо чечими кабыл алынат.
Заводдук методдун структурасы
Жогорудагы диаграмма заводдук ыкма үлгүсүнүн жалпы структурасын көрсөтөт. Бул жерде дагы эмне маанилүү?- Жаратуучу классы фабрикалык ыкмадан башка, өнүмдөр менен өз ара аракеттенүүчү бардык ыкмаларды ишке ашырууну камтыйт.
- Абстракттуу метод
factoryMethod()
класстын бардык урпактары тарабынан ишке ашырылышы керекCreator
. - Класс түздөн-түз продуктуну чыгарган
ConcreteCreator
ыкманы ишке ашырат .factoryMethod()
- Бул класс белгилүү бир буюмдарды түзүү үчүн жооптуу болуп саналат. Бул өнүмдөрдү түзүү жөнүндө маалыматы бар жалгыз класс.
- Бардык продуктылар жалпы интерфейсти ишке ашырышы керек - жалпы продукт классынын тукумдары болушу керек. Бул продукттарды колдонгон класстар аларда конкреттүү ишке ашыруунун ордуна абстракция деңгээлинде иштеши үчүн зарыл.
GO TO FULL VERSION