На този етап вероятно вече сте се сблъскали с шаблони за проектиране. Например, singleton .

Нека си припомним Howво представляват шаблоните, защо са необходими и Howво представляват шаблоните за създаване (singleton е пример). Ще проучим и нов модел: фабричния метод.

В разработката на софтуер моделът на дизайн е повторяема архитектурна конструкция, която представлява решение на проектен проблем в рамките на няHowъв повтарящ се контекст.

Обикновено моделът не е окончателно решение, което може директно да се преобразува в code. Това е само моделно решение на проблем, което може да се използва в различни ситуации.

Креативните модели са дизайнерски модели, които се занимават с процеса на създаване на обекти. Те правят възможно създаването на система, която е независима от метода, използван за създаване, композиране и представяне на обекти.

Фабричен метод е модел за създаване на дизайн, който дефинира общ интерфейс за създаване на обекти в родителски клас, като дава възможност на неговите потомци да създават тези обекти. По време на създаването потомците могат да определят кой клас да бъде създаден.

Какъв проблем решава шаблонът?

Представете си, че решите да създадете програма за доставка. Първоначално ще наемете куриери с коли и ще използвате aКолаобект, който да представлява превозно средство за доставка в програмата. Куриери доставят пакети от точка А до точка Б и т.н. Лесна работа.

Програмата набира популярност. Вашият бизнес се разраства и искате да се разширите на нови пазари. Например, можете да започнете да доставяте храна и превоз на товари. В този случай храната може да бъде доставена от куриери пеша, на скутери и велосипеди, но за товари са необходими камиони.

Сега трябва да следите няколко неща (кога, на кого, Howво и колко ще бъде доставено), включително колко всеки куриер може да носи. Новите видове транспорт имат различни скорости и капацитет. Тогава забелязвате, че повечето обекти във вашата програма са силно обвързани сКолаклас. Разбирате, че за да накарате вашата програма да работи с други методи за доставка, ще трябва да пренапишете съществуващата codeова база и да правите това отново всеки път, когато добавяте ново превозно средство.

Резултатът е ужасяващ code, пълен с условни изрази, които изпълняват различни действия в зависимост от вида на транспорта.

Решението

Моделът на фабричния метод предполага създаване на обекти чрез извикване на специален фабричен метод, instead of директно използване на оператора new . Подкласовете на класа, който има фабричния метод, могат да променят създадените обекти на конкретните превозни средства. На пръв поглед това може да изглежда безсмислено: просто сме преместor извикването на конструктора от едно място в програмата на друго. Но сега можете да замените фабричния метод в подклас, за да промените вида на създавания транспорт.

Нека да разгледаме класовата диаграма за този подход:

За да работи тази система, всички върнати обекти трябва да имат общ интерфейс. Подкласовете ще могат да произвеждат обекти от различни класове, които имплементират този интерфейс.

Например, класовете Truck и Car имплементират интерфейса CourierTransport с метод за доставка . Всеки от тези класове прилага метода по различен начин: камионите доставят товари, докато колите доставят храна, пакети и т.н. Фабричният метод в класа TruckCreator връща обект камион, а класът CarCreator връща обект автомобил.

За клиента на фабричния метод няма разлика между тези обекти, тъй като той ще ги третира като няHowъв вид абстрактен CourierTransport . Клиентът ще се интересува много дали обектът има метод за доставка, но How точно работи този метод не е важно.

Внедряване в Java:


public interface CourierTransport {
	void deliver();
}
public class Car implements CourierTransport {
	@Override
	public void deliver() {
    		System.out.println("The package is being delivered by car");
	}
}
public class Truck implements CourierTransport {
	@Override
	public void deliver() {
    		System.out.println("The freight is being delivered by truck");
	}
}
public abstract class CourierTransportCreator {
	public abstract CourierTransport createTransport();
}
public class CarCreator extends CourierTransportCreator {
	@Override
	public CourierTransport createTransport() {
    		return new Car();
	}
}
public class TruckCreator extends CourierTransportCreator {
	@Override
	public CourierTransport createTransport() {
    		return new Truck();
	}
}
 
public class Delivery {
	private String address;
	private CourierTransport courierTransport;
 
	public void Delivery() {
	}
 
	public Delivery(String address, CourierTransport courierTransport) {
    	this.address = address;
    	this.courierTransport = courierTransport;
	}
 
	public CourierTransport getCourierTransport() {
    		return courierTransport;
	}
 
	public void setCourierTransport(CourierTransport courierTransport) {
    		this.courierTransport = courierTransport;
	}
 
	public String getAddress() {
    		return address;
	}
 
	public void setAddress(String address) {
    		this.address = address;
	}
}
public static void main(String[] args) {
    	// Accept a new type of order from the database (pseudocode)
    	String type = database.getTypeOfDeliver();
 
    	Delivery delivery = new Delivery();
    	
    	// Set the transport for delivery
        delivery.setCourierTransport(getCourierTransportByType(type));
    	
    	// Make the delivery
        delivery.getCourierTransport().deliver();
 
	}
 
	public static CourierTransport getCourierTransportByType(String type) {
    	switch (type) {
        	case "CarDelivery":
            	return new CarCreator().createTransport();
        	case "TruckDelivery":
            	return new TruckCreator().createTransport();
        	default:
            	throw new RuntimeException();
	    }
	}
    

Ако искаме да създадем нов обект за доставка, тогава програмата автоматично създава подходящ транспортен обект.

Кога трябва да приложим този модел?

1. Когато не знаете предварително типовете и зависимостите на обектите, с които вашият code трябва да работи.

Фабричният метод разделя codeа за производство на форми на транспорт от codeа, който използва транспорта. В резултат на това codeът за създаване на обекти може да бъде разширен, без да се докосва останалата част от codeа.

Например, за да добавите поддръжка за нов тип транспорт, трябва да създадете нов подклас и да дефинирате фабричен метод в него, който връща екземпляр на новия транспорт.

2. Когато искате да спестите системни ресурси, като използвате повторно съществуващи обекти, instead of да създавате нови.

Този проблем обикновено възниква при работа с ресурсоемки обекти, като връзки към бази данни, файлови системи и др.

Помислете за стъпките, които трябва да предприемете, за да използвате повторно съществуващи обекти:

  1. Първо, трябва да създадете споделено хранorще, за да съхранявате всички обекти, които създавате.

  2. Когато заявявате нов обект, трябва да погледнете в хранorщето и да проверите дали съдържа наличен обект.

  3. Върнете обекта към клиентския code.

  4. Но ако няма налични обекти, създайте нов и го добавете към хранorщето.

Целият този code трябва да бъде поставен някъде, където няма да претрупва клиентския code. Най-удобното място би бил конструкторът, тъй като имаме нужда от всички тези проверки само когато създаваме обекти. Уви, конструкторът винаги създава нов обект - той не може да върне съществуващ обект.

Това означава, че е необходим друг метод, който може да върне Howто съществуващи, така и нови обекти. Това ще бъде фабричният метод.

3. Когато искате да позволите на потребителите да разширяват части от вашата рамка or библиотека.

Потребителите могат да разширят вашите рамкови класове чрез наследяване. Но How да накарате рамката да създава обекти от тези нови класове, а не от стандартните?

Решението е да позволим на потребителите да разширяват не само компонентите, но и класовете, които създават тези компоненти. И за това създаващите класове трябва да имат специфични методи за създаване, които могат да бъдат дефинирани.

Предимства

  • Отделя клас от конкретни транспортни класове.
  • Съхранява codeа за създаване на форми на транспорт на едно място, което прави codeа по-лесен за поддръжка.
  • Опростява добавянето на нови видове транспорт към програмата.
  • Реализира принципа отворено-затворено.

Недостатъци

Може да доведе до големи йерархии на паралелни класове, тъй като всеки продуктов клас трябва да има свой собствен подклас създател.

Нека да обобщим

Научихте за модела на фабричния метод и видяхте една възможна реализация. Този модел често се използва в различни библиотеки, които предоставят обекти за създаване на други обекти.

Използвайте модела на фабричния метод, когато искате лесно да добавяте нови обекти от подкласове на съществуващи класове, за да взаимодействате с основната си бизнес логика и да не раздувате codeа си поради различни контексти.