Сцены
Примеры использования шаблона-прототипа шаблона-поверхностного клонирования и глубокого клонирования в Java:
Пример использования режима прототипа изначально записан выше, а праздничный день или событие — ниже.
Пример отправки писем.
шаблон прототипа
Простота шаблона прототипа (Prototype Pattern) уступает только шаблону singleton и шаблону iterator. Именно из-за своей простоты его можно использовать во многих сценариях.
Он определяется следующим образом:
Укажите типы объектов, которые необходимо создать, используя экземпляр-прототип, и создайте новые объекты, скопировав этот прототип.
(Используйте экземпляры прототипов, чтобы указать тип создаваемых объектов, и создавайте новые объекты, копируя эти прототипы.)
Просто, так легко! Ядром режима прототипа является метод клонирования, с помощью которого объект копируется, а Java предоставляет интерфейс Cloneable для маркировки.
Этот объект можно копировать, почему он называется «маркировка»? Откройте справку JDK, чтобы увидеть, что у Cloneable нет метода, этот интерфейс — просто маркер,
Только объекты с этой меткой в JVM могут быть скопированы. Итак, как мы можем преобразовать «возможно скопированное» в «можно скопировать»?
Метод заключается в переопределении метода clone(), да, вы правильно прочитали, переопределении метода clone().
Плюсы шаблона прототипа
Превосходное представление
Режим прототипа — это копия двоичного потока памяти, производительность которого намного выше, чем непосредственное обновление объекта, особенно когда в теле цикла должно быть сгенерировано большое количество объектов.
Шаблон прототипа может лучше отражать его преимущества.
избежать ограничений конструктора
В этом его преимущество и недостаток, копируя прямо в память, конструктор выполняться не будет**. Преимущество в том, что ограничения уменьшаются,
Недостатком также является снижение ограничений, что необходимо учитывать в практических приложениях.
Сценарии использования шаблона прототипа
Сценарий оптимизации ресурсов
Инициализация класса требует обработки большого количества ресурсов, включая данные, аппаратные ресурсы и т. д.
Сценарии с требованиями к производительности и безопасности
Генерация объекта через new требует очень громоздкой подготовки данных или прав доступа, поэтому можно использовать режим прототипа.
Сценарии с несколькими модификаторами для одного объекта
Когда объект должен быть доступен другим объектам, и каждому вызывающему объекту может потребоваться изменить его значение, вы можете рассмотреть возможность использования режима прототипа для копирования нескольких объектов для использования вызывающим объектом.
В реальных проектах шаблон прототипа редко появляется сам по себе и обычно появляется вместе с шаблоном фабричного метода, создавая объект с помощью метода клонирования.
Затем он предоставляется вызывающей стороне фабричным методом.
Примечание о шаблоне прототипа
конструктор не будет выполнен
Класс A, реализующий Cloneable и переписывающий метод clone, имеет конструкцию без аргументов или конструкцию B с параметрами и генерирует объект S с помощью нового ключевого слова.
Затем с помощью S.clone() генерируется новый объект T, после чего конструктор B не будет выполняться при копировании объекта. Для получения подробной информации см. пример кода.
мелкая копия и глубокая копия
Примечание. Не рекомендуется смешивать глубокое и поверхностное копирование, особенно когда речь идет о наследовании классов, ситуация, когда родительский класс имеет несколько ссылок, очень сложна.
Предлагаемое решение состоит в том, чтобы реализовать глубокое копирование и поверхностное копирование отдельно.
Для поверхностного и глубокого копирования см. пример кода.
клон и два последних врага
Клон объекта конфликтует с ключевым словом final в объекте.Если вы хотите использовать метод клонирования, не добавляйте ключевое слово final к переменным-членам класса.
Примечание:
Блог:
властный мошеннический темперамент blog_CSDN Blog-C#, Architecture Road, Blogger in SpringBoot
выполнить
1. Банковский фестиваль рассылает электронное письмо с уведомлением о розыгрыше.
Новый код шаблона рекламного письма
@Data
public class AdvTemplate {
//广告信名称
private String advSubject = "xx银行抽奖活动";
//广告信内容
private String advContext = "抽奖活动通知:......";
}
2. Новый код почтового класса
//邮件类代码
@Data
public class Mail {
//收件人
private String receiver;
//邮件名称
private String subject;
//称谓
private String appellation;
//内容
private String context;
//邮件底部,一般是加上"xxx版权所有"等信息
private String tail;
public Mail(AdvTemplate advTemplate){
this.context = advTemplate.getAdvContext();
this.subject = advTemplate.getAdvSubject();
}
}
3. Категория сцены
//场景类
public class Client {
//发送账单的数量
private static int MAX_COUNT = 6;
public static void main(String[] args) {
//模拟发送邮件
int i =0;
//把模板定义出来,这个一般从数据库中获取
Mail mail = new Mail(new AdvTemplate());
mail.setTail("badaoxxx版权所有");
while (i<MAX_COUNT){
//每封邮件不同的地方
mail.setAppellation(i+"先生/女士");
mail.setReceiver(i+"[email protected]");
sendMail(mail);
i++;
}
}
public static void sendMail(Mail mail){
System.out.println("标题:"+mail.getSubject()+"\t收件人:"+mail.getReceiver()+"\t...发送成功!");
}
}
вопрос:
Для однопоточной отправки нужно изменить sendMail на многопоточность, и будут проблемы: первый почтовый объект будет сгенерирован и запущен в потоке 1, но еще не отправлен;
Также запускается поток 2, и получатель и заголовок почтового объекта меняются напрямую.Поток не является безопасным.Конечно, есть много других решений.
Один из них заключается в использовании шаблона нового типа для решения этой проблемы: через функцию копирования объекта для решения этой проблемы.
4. Модифицированный почтовый класс
//修改后的邮件类
@Data
public class MailExtend implements Cloneable{
//收件人
private String receiver;
//邮件名称
private String subject;
//称谓
private String appellation;
//内容
private String context;
//邮件底部,一般是加上"xxx版权所有"等信息
private String tail;
public MailExtend(AdvTemplate advTemplate){
this.context = advTemplate.getAdvContext();
this.subject = advTemplate.getAdvSubject();
}
@Override
public MailExtend clone() throws CloneNotSupportedException {
MailExtend mailExtend = null;
mailExtend = (MailExtend) super.clone();
return mailExtend;
}
}
5. Модифицированный класс сцены
//修改后的场景类
public class ClientExtend {
//发送账单的数量
private static int MAX_COUNT = 6;
public static void main(String[] args) throws CloneNotSupportedException {
//模拟发送邮件
int i =0;
//把模板定义出来,这个一般从数据库中获取
MailExtend mail = new MailExtend(new AdvTemplate());
mail.setTail("badaoxxx版权所有");
while (i<MAX_COUNT){
//每封邮件不同的地方
MailExtend cloneMail = mail.clone();
mail.setAppellation(i+"先生/女士");
mail.setReceiver(i+"[email protected]");
sendMail(cloneMail);
i++;
}
}
public static void sendMail(MailExtend mail){
System.out.println("标题:"+mail.getSubject()+"\t收件人:"+mail.getReceiver()+"\t...发送成功!");
}
}
Текущий результат остается неизменным, и это не имеет значения, даже если sendMail является многопоточным.
Функция mail.clone() в классе Client копирует объект для создания нового объекта, который совпадает с исходным объектом, а затем изменяет подробные данные.
Например, установка заголовка, адреса получателя и т. д. Этот режим, который не генерирует объект через ключевое слово new, а реализуется через копирование объекта, называется режимом прототипа.
6. Убедитесь, что конструктор после клонирования не будет выполняться
//构造函数不会被执行
public class Thing implements Cloneable{
public Thing(){
System.out.println("构造函数被执行了...");
}
@Override
public Thing clone() throws CloneNotSupportedException {
Thing thing = null;
thing = (Thing)super.clone();
return thing;
}
}
Напишите другой клиент, чтобы скопировать объект
public class TestClient {
public static void main(String[] args) throws CloneNotSupportedException {
Thing thing = new Thing();
Thing cloneThing = thing.clone();
}
}
Из результатов выполнения видно, что конструктор не выполняется при копировании объекта.
Принцип метода клонирования класса Object заключается в копировании из памяти в виде бинарного потока и перераспределении блока памяти.
7. Поверхностное и глубокое клонирование
См. пример поверхностного клонирования
public class QianClone implements Cloneable{
//定义一个私有变量
private ArrayList<String> arrayList = new ArrayList<>();
@Override
public QianClone clone() throws CloneNotSupportedException {
QianClone thing = null;
thing = (QianClone)super.clone();
return thing;
}
public void setValue(String value){
this.arrayList.add(value);
}
public ArrayList<String> getValue(){
return this.arrayList;
}
}
Класс сцены, называемый мелким клоном
public class QianCloneClient {
public static void main(String[] args) throws CloneNotSupportedException {
QianClone qianClone = new QianClone();
qianClone.setValue("张三");
QianClone qianCloneClone = qianClone.clone();
qianCloneClone.setValue("李四");
System.out.println(qianClone.getValue());
//[张三, 李四]
}
}
Добавьте приватную переменную arrayList, а затем запустите результат не только Чжан Сан, но и Ли Си.
Это связано с тем, что метод clone класса Object копирует только объект, а массивы и ссылочные объекты внутри объекта не копируются и по-прежнему указывают на внутренний адрес элемента исходного объекта.
Эта копия является поверхностной копией. Два объекта имеют общую частную переменную, и каждый может изменить ее, если вы ее измените. Итак, почему тип String можно использовать в классе Mail,
без проблем, вызванных мелкими копиями. Поскольку внутренние массивы и объекты не копируются, другие примитивные типы int, long, cha и т. д. и String будут скопированы.
Пример глубокого копирования
//深拷贝
public class ShenClone implements Cloneable{
//定义一个私有变量
private ArrayList<String> arrayList = new ArrayList<>();
@Override
public ShenClone clone() throws CloneNotSupportedException {
ShenClone thing = null;
thing = (ShenClone)super.clone();
thing.arrayList = (ArrayList<String>) this.arrayList.clone();
return thing;
}
public void setValue(String value){
this.arrayList.add(value);
}
public ArrayList<String> getValue(){
return this.arrayList;
}
}
Класс сцены глубокого копирования
public class ShenCloneClient {
public static void main(String[] args) throws CloneNotSupportedException {
ShenClone shenClone = new ShenClone();
shenClone.setValue("张三");
ShenClone shenClone1 = shenClone.clone();
shenClone1.setValue("李四");
System.out.println(shenClone.getValue());
//[张三]
}
}
Делайте независимые копии частных переменных класса.
Этот метод реализует полную копию, между двумя объектами нет связи, и они не влияют друг на друга, это глубокая копия.