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

Для реализации шаблона проектирования прототипа в Java требуется клонируемый класс интерфейса.

Примечание. Класс клонируемого интерфейса всегда возвращает тип объекта, а не общий, поскольку разработчику необходимо преобразовать каждый объект, клонированный с помощью клонируемого интерфейса.

Важно: при клонировании объектов разработчику необходимо учитывать, какой тип клонирования подходит для данной архитектуры. Есть два типа клонирования,

1. Поверхностное копирование

2. Глубокое копирование

Поверхностное копирование. Скопируйте объект первого уровня и ссылки на новый объект.

Примечание. Это может привести к другой серьезной проблеме, если элементы значений будут изменены с помощью какой-либо другой ссылки.

Глубокое копирование: при глубоком копировании он не только клонирует объект первого уровня, но также копирует каждое значение и ссылки на новый объект.

Пример. Предположим, что авиакомпании требуется программное обеспечение для обработки авиабилетов, и доступны три типа билетов.

Шаг 1:

Создайте абстрактный класс с именем AirlineTicket.

package PrototypeExample;
 
 public abstract class AirlineTicket implements Cloneable {
     private String flightNumber;
     private double duration;
     private String departure;
     private String arrival;
     private String seatNumber;
 
     public String getFlightNumber() {
         return flightNumber;
     }
 
     public void setFlightNumber(String flightNumber) {
         this.flightNumber = flightNumber;
     }
 
     public double getDuration() {
         return duration;
     }
 
     public void setDuration(double duration) {
         this.duration = duration;
     }
 
     public String getDeparture() {
         return departure;
     }
 
     public void setDeparture(String departure) {
         this.departure = departure;
     }
 
     public String getArrival() {
         return arrival;
     }
 
     public void setArrival(String arrival) {
         this.arrival = arrival;
     }
 
     public String getSeatNumber() {
         return seatNumber;
     }
 
     public void setSeatNumber(String seatNumber) {
         this.seatNumber = seatNumber;
     }
 
     @Override
     protected Object clone() throws CloneNotSupportedException {
         return super.clone();
     }
 }

Реализуйте клонируемый интерфейс для клонирования экземпляров. А также реализовать сеттеры и геттеры.

Шаг 2:

Создайте дочерние классы класса AirlineTicket.

Эконом-класс:

package PrototypeExample;
public class EconomyClass extends AirlineTicket{
    private boolean needAssistant;
public boolean isNeedAssistant() {
        return needAssistant;
    }
public void setNeedAssistant(boolean needAssistant) {
        this.needAssistant = needAssistant;
    }
@Override
    public String toString() {
        return "EconomyClass{" +
                "flightNumber='" + super.getFlightNumber() + '\'' +
                ", duration=" + super.getDuration() +
                ", departure='" + super.getDeparture() + '\'' +
                ", arrival='" + super.getArrival() + '\'' +
                ", seatNumber='" + super.getSeatNumber() + '\'' +
                "needAssistant=" + needAssistant +
                '}';
    }
}

Бизнес-класс:

package PrototypeExample;
public class BusinessClass extends AirlineTicket{
    private boolean needOnBoardDrink;
    private boolean loungeAccess;
    private boolean VIPTransport;
public boolean isNeedOnBoardDrink() {
        return needOnBoardDrink;
    }
public void setNeedOnBoardDrink(boolean needOnBoardDrink) {
        this.needOnBoardDrink = needOnBoardDrink;
    }
public boolean isLoungeAccess() {
        return loungeAccess;
    }
public void setLoungeAccess(boolean loungeAccess) {
        this.loungeAccess = loungeAccess;
    }
public boolean isVIPTransport() {
        return VIPTransport;
    }
public void setVIPTransport(boolean VIPTransport) {
        this.VIPTransport = VIPTransport;
    }
@Override
    public String toString() {
        return "BusinessClass{" +
                "flightNumber='" + super.getFlightNumber() + '\'' +
                ", duration=" + super.getDuration() +
                ", departure='" + super.getDeparture() + '\'' +
                ", arrival='" + super.getArrival() + '\'' +
                ", seatNumber='" + super.getSeatNumber() + '\'' +
                ", needOnBoardDrink=" + needOnBoardDrink +
                ", loungeAccess=" + loungeAccess +
                ", VIPTransport=" + VIPTransport +
                '}';
    }
}

Первый класс:

package PrototypeExample;
public class FirstClass extends AirlineTicket{
    private boolean needOnBoardDrink;
    private boolean loungeAccess;
public boolean isNeedOnBoardDrink() {
        return needOnBoardDrink;
    }
public void setNeedOnBoardDrink(boolean needOnBoardDrink) {
        this.needOnBoardDrink = needOnBoardDrink;
    }
public boolean isLoungeAccess() {
        return loungeAccess;
    }
public void setLoungeAccess(boolean loungeAccess) {
        this.loungeAccess = loungeAccess;
    }
@Override
    public String toString() {
        return "FirstClass{" +
                "flightNumber='" + super.getFlightNumber() + '\'' +
                ", duration=" + super.getDuration() +
                ", departure='" + super.getDeparture() + '\'' +
                ", arrival='" + super.getArrival() + '\'' +
                ", seatNumber='" + super.getSeatNumber() + '\'' +
                ", needOnBoardDrink=" + needOnBoardDrink +
                ", loungeAccess=" + loungeAccess +
                '}';
    }
}

Создайте геттеры и сеттеры для каждого класса.

Шаг 3.

Создайте класс enum для представления типов авиабилетов.

package PrototypeExample;
public enum AirlineTicketType {
    ECONOMY,
    BUSINESS,
    FIRST
}

Шаг 4:

Создайте класс реестра.

Этот класс отвечает за первоначальное создание объекта.

Примечание. Разработчику необходимо использовать «новые» ключевые слова только при первоначальном создании экземпляра.

package PrototypeExample;
import java.util.HashMap;
import java.util.Map;
public class Registry {
    private Map<AirlineTicketType, AirlineTicket> tickets = new HashMap<>();
public Registry() {
        this.initialize();
    }
public AirlineTicket getTicket (AirlineTicketType airlineTicketType) {
        AirlineTicket airlineTicket = null;
        try {
            airlineTicket = (AirlineTicket) tickets.get(airlineTicketType).clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return airlineTicket;
    }
private void initialize() {
        EconomyClass economyClass = new EconomyClass();
        economyClass.setFlightNumber("AB1");
        economyClass.setDuration(4.5);
        economyClass.setDeparture("CMB");
        economyClass.setArrival("KUL");
        economyClass.setSeatNumber("AA12");
BusinessClass businessClass = new BusinessClass();
        businessClass.setFlightNumber("AB1");
        businessClass.setDuration(4.5);
        businessClass.setDeparture("CMB");
        businessClass.setArrival("KUL");
        businessClass.setSeatNumber("BB21");
        businessClass.setNeedOnBoardDrink(true);
        businessClass.setLoungeAccess(true);
        businessClass.setVIPTransport(true);
FirstClass firstClass = new FirstClass();
        firstClass.setFlightNumber("AB1");
        firstClass.setDuration(4.5);
        firstClass.setDeparture("CMB");
        firstClass.setArrival("KUL");
        firstClass.setSeatNumber("CC34");
        firstClass.setNeedOnBoardDrink(true);
        firstClass.setLoungeAccess(true);
tickets.put(AirlineTicketType.ECONOMY, economyClass);
        tickets.put(AirlineTicketType.BUSINESS, businessClass);
        tickets.put(AirlineTicketType.FIRST, firstClass);
    }
}

Создайте конструктор для класса. В этом конструкторе функция вызова под названием «инициализация» создает начальные объекты. После создания исходного объекта добавьте в реестр следующие экземпляры авиабилетов. Наконец, создайте функции get для получения уже инициализированных авиабилетов.

Шаг 5.

Храните и извлекайте авиабилеты.

package PrototypeExample;
public class Application {
    public static void main(String[] args) {
        Registry registry = new Registry();
EconomyClass economyClass = (EconomyClass) registry.getTicket(AirlineTicketType.ECONOMY);
        System.out.println("Initial Values........");
        System.out.println("Economy Class: " + economyClass);
economyClass.setFlightNumber("CX400");
        economyClass.setDuration(0.0);
        economyClass.setDeparture("CMB");
        economyClass.setArrival("HKG");
        economyClass.setSeatNumber("CE14");
        economyClass.setNeedAssistant(true);
        System.out.println("After Setting New Values........");
        System.out.println("Economy Class: " + economyClass);
EconomyClass economyClass1 = (EconomyClass) registry.getTicket(AirlineTicketType.ECONOMY);
        System.out.println("New Economy Class Instance Values........");
        System.out.println("Economy Class: " + economyClass1);
}
}

Как видите, мы можем установить новые значения для авиабилетов и сохранить новые авиабилеты. А также при создании нового экземпляра из эконом-класса снова присваивается начальное значение, которое уже предоставлено из-за клонируемого интерфейса.

Преимущества шаблона проектирования прототипа:

· Разработчики могут избежать накладных расходов и проблем с производительностью процесса создания объекта.

Недостатки шаблона проектирования прототипа:

· Перебор для проекта, в котором используется очень мало объектов и/или не делается упор на расширение цепочек прототипов.

· Он также скрывает от клиента конкретные классы продуктов.

Я надеюсь, что теперь вы в состоянии понять, что такое шаблон проектирования прототипа, как реализовать шаблон проектирования прототипа и каковы его преимущества и недостатки.