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

Всъщност има много от тези модели и те могат да бъдат класифицирани според специфичното им преднаmeaning.

Класификация на моделите

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

Обикновено моделът се характеризира с проблема, който решава. Нека да разгледаме няколко модела, които най-често срещаме, когато работим с Java:

модел Преднаmeaning
Сингълтън Вече сме запознати с този модел — използваме го за създаване и достъп до клас, който не може да има повече от един екземпляр.
Итератор Ние също сме запознати с този. Знаем, че този модел ни позволява да обикаляме обект на колекция, без да разкриваме неговото вътрешно представяне. Използва се с колекции.
Адаптер Този модел свързва несъвместими обекти, така че да могат да работят заедно. Мисля, че името на модела на адаптера ви помага да си представите Howво точно прави това. Ето един прост пример от реалния живот: USB адаптер за стенен контакт.
Шаблонен метод

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

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

Шаси -> Каросерия -> Двигател -> Интериор на кабината

Ако поставим подсилена рамка, по-мощен двигател or интериор с допълнително осветление, не се налага да променяме алгоритъма и абстрактната последователност остава същата.

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

В Java.io следните класове имплементират шаблони:

модел Където се използва в java.io
Адаптер
Шаблонен метод
Декоратор

Модел на декоратор

Нека си представим, че описваме модел за домашен дизайн.

Най-общо подходът изглежда така:

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

Създаваме абстрактен клас House:

public abstract class House {
	String info;

	public String getInfo() {
    	return info;
	}

	public abstract int getPrice();
}

Тук имаме 2 метода:

  • getInfo() връща информация за името и характеристиките на нашата къща;
  • getPrice() връща цената на текущата конфигурация на къщата.

Разполагаме и със стандартни изпълнения на къщи — тухлени и дървени:

public class BrickHouse extends House {

	public BrickHouse() {
    	info = "Brick House";
	}

	@Override
	public int getPrice() {
    	return 20_000;
	}
}

public class WoodenHouse extends House {

	public WoodenHouse() {
    	info = "Wooden House";
	}

	@Override
	public int getPrice() {
    	return 25_000;
	}
}

И двата класа наследяват класа Къща и отменят метода на цената му, задавайки персонализирана цена за стандартна къща. Задаваме името в конструктора.

След това трябва да напишем класове за декоратори. Тези класове също ще наследят класа House . За да направим това, създаваме абстрактен клас декоратор.

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

abstract class HouseDecorator extends House {
}

След това създаваме реализации на декоратор. Ще създадем няколко класа, които ни позволяват да добавим допълнителни функции към къщата:

public class SecondFloor extends HouseDecorator {
	House house;

	public SecondFloor(House house) {
    	this.house = house;
	}

	@Override
	public int getPrice() {
    	return house.getPrice() + 20_000;
	}

	@Override
	public String getInfo() {
    	return house.getInfo() + " + second floor";
	}
}
Декоратор, който добавя втори етаж към нашата къща

Конструкторът на декоратора приема къща, която ще "украсим", т.е. ще добавим модификации. И ние отменяме методите getPrice() и getInfo() , връщайки информация за новата актуализирана къща въз основа на старата.

public class Garage extends HouseDecorator {

	House house;
	public Garage(House house) {
    	this.house = house;
	}

	@Override
	public int getPrice() {
    	return house.getPrice() + 5_000;
	}

	@Override
	public String getInfo() {
    	return house.getInfo() + " + garage";
	}
}
Декоратор, който добавя гараж към къщата ни

Сега можем да актуализираме къщата си с декоратори. За да направим това, трябва да създадем къща:

House brickHouse = new BrickHouse();

След това задаваме нашитекъщапроменлива, равна на нов декоратор, преминаващ в нашата къща:

brickHouse = new SecondFloor(brickHouse);

Нашитекъщапроменлива сега е къща с втори етаж.

Нека да разгледаме случаите на употреба, включващи декоратори:

Примерен code Изход
House brickHouse = new BrickHouse();

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());

Тухлена къща

20 000

House brickHouse = new BrickHouse();

  brickHouse = new SecondFloor(brickHouse);

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());

Тухлена къща + втори етаж

40 000

House brickHouse = new BrickHouse();


  brickHouse = new SecondFloor(brickHouse);
  brickHouse = new Garage(brickHouse);

  System.out.println(brickHouse.getInfo());
  System.out.println(brickHouse.getPrice());

Тухлена къща + втори етаж + гараж

45 000

House woodenHouse = new SecondFloor(new Garage(new WoodenHouse()));

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());

Дървена къща + гараж + втори етаж

50 000

House woodenHouse = new WoodenHouse();

  House woodenHouseWithGarage = new Garage(woodenHouse);

  System.out.println(woodenHouse.getInfo());
  System.out.println(woodenHouse.getPrice());

  System.out.println(woodenHouseWithGarage.getInfo());
  System.out.println(woodenHouseWithGarage.getPrice());

Дървена къща

25 000

Дървена къща + гараж

30 000

Този пример илюстрира ползата от надграждане на обект с декоратор. Така че не променихмедървена къщасамия обект, но instead of това създаде нов обект на базата на стария. Тук можем да видим, че предимствата идват с недостатъци: всеки път създаваме нов обект в паметта, увеличавайки потреблението на памет.

Вижте тази UML диаграма на нашата програма:

Декораторът има супер проста реализация и динамично променя обектите, като ги надгражда. Декораторите могат да бъдат разпознати от техните конструктори, които приемат като параметри обекти от същия абстрактен тип or интерфейс като текущия клас. В Java този модел се използва широко в I/O класове.

Например, Howто вече отбелязахме, всички подкласове на java.io.InputStream , OutputStream , Reader и Writer имат конструктор, който приема обекти от същите класове.