Шаблон проектирования параллелизма Java - неизменяемый шаблон (неизменяемый)

Java задняя часть Шаблоны проектирования Immutable.js
Шаблон проектирования параллелизма Java - неизменяемый шаблон (неизменяемый)

1. Что такое неизменяемый режим?

Неизменяемость, как следует из названия, означает, что объект не может быть изменен после его создания! Точнее, после создания объекта его属性值Не могу измениться! Все операции над исходным объектом возвращают копию исходного объекта. Итак, как это сделать в java? Ответ заключается в использованииfinalключевые слова. Ниже я расскажу о том, как спроектировать «неизменяемый» объект.

Проектирование неизменяемого класса должно следовать следующим пунктам:

  • 1. Все свойства класса объявлены какprivate, убрать всеsetterметод предотвращения прямого изменения внешнего мира
  • 2. Объявление класса принимаетfinalИзмените его, чтобы гарантировать, что ни один родительский класс не изменит его.
  • 3. Свойства класса объявляются какfinal, если тип объекта является типом переменной, он должен быть переупакован,newобъект возвращен

Вот пример неизменяемого класса:

package com.wokao66;

/**
 * 不可变类
 * @author: huangjiawei
 * @since: 2018年4月2日
 * @version: $Revision$ $Date$ $LastChangedBy$
 *
 */
//采用fianl修饰,防止子类继承
public final class Immutable {

	/**
	 * 所有的属性private且final
	 */
	private final String name;
	private final int age;

	/**
	 * 构造方法
	 * @param name
	 * @param age
	 */
	public Immutable(String name, int age) {
		this.name = name;
		this.age = age;
	}

	/**
	 * 去除所有的setter方法
	 */
	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	/**
	 * 将年龄增加10岁
	 * @param newAge
	 * @return
	 */
	public Immutable addAge(int newAge) {
		/**
		 * 重新返回一个对象
		 */
		return new Immutable(this.getName(), newAge + this.getAge());
	}

	public static void main(String[] args) {
		Immutable immutable = new Immutable("a", 12);
		System.err.println(immutable.getAge());
		Immutable newImmutable = immutable.addAge(10);
		System.err.println(immutable.getAge());
		System.err.println(newImmutable.getAge());
	}
}

результат операции:

12
12
22

Во-вторых, он был случайно спроектирован как изменяемый объект!

Если приведенный выше неизменяемый класс разработан таким образом, он становится изменяемым!

package com.wokao66;

import java.util.Date;

/**
 * 人生处处有惊喜,一不小心就掉进陷阱里
 * @author: huangjiawei
 * @since: 2018年4月2日
 * @version: $Revision$ $Date$ $LastChangedBy$
 */
public final class Mutable {

	/**
	 * 所有的属性private且final
	 */
	private final String name;
	private final int age;
	private final Date birthday;

	/**
	 * 构造方法
	 * @param name
	 * @param age
	 */
	public Mutable(String name, int age, Date birthday) {
		this.name = name;
		this.age = age;
		this.birthday = birthday;
	}

	/**
	 * 去除所有的setter方法
	 */
	public String getName() {
		return name;
	}

	public int getAge() {
		return age;
	}

	public Date getBirthday() {
		return birthday;
	}

	/**
	 * 将年龄增加10岁
	 * @param newAge
	 * @return
	 */
	public Mutable addAge(int newAge) {
		/**
		 * 重新返回一个对象
		 */
		return new Mutable(this.getName(), newAge + this.getAge(), this.birthday);
	}

	public static void main(String[] args) {
		Date birthday = new Date();
		Mutable xiaoming = new Mutable("小明", 21, birthday);
		System.err.println("小明的生日为 : " + xiaoming.getBirthday());

		//我设置下我的生日,你会发现我的生日居然可以改变
		birthday.setTime(System.currentTimeMillis() + 1000000000);
		System.err.println("小明的生日为 : " + xiaoming.getBirthday());
	}
}

Результат выглядит следующим образом:

小明的生日为 : Mon Apr 02 15:33:44 CST 2018
小明的生日为 : Sat Apr 14 05:20:24 CST 2018

Видимые результаты изменились, потому чтоDateявляется изменяемым типом. Измените конструктор следующим образом:

	/**
	 * 构造方法
	 * @param name
	 * @param age
	 */
	public Mutable(String name, int age, Date birthday) {
		this.name = name;
		this.age = age;
		//对于可变类型的属性,初始化的时候应该重新生成一个
		//this.birthday = new Date(birthday.getTime());
		this.birthday = birthday;
	}

Результат выглядит следующим образом:

小明的生日为 : Mon Apr 02 15:36:24 CST 2018
小明的生日为 : Mon Apr 02 15:36:24 CST 2018

Во-вторых, преимущества и недостатки неизменяемого режима и сценариев приложений.

преимущество:

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

недостаток:

  • 1. Новый объект создается каждый раз, когда он возвращается, и память будет иметь определенные накладные расходы, которые нелегко переработать сборщику мусора, что приводит к пустой трате ресурсов.

Сценарии применения:

  • 1. Не подходит для сцен с большими объектами и частым созданием, т.к. большие объекты и частое создание легко приведут к утечкам памяти
  • 2. Значения, подходящие для представления абстрактных типов данных, таких как числа, перечисления или цвета.
  • 3. Подходит для синхронизации в многопоточной среде без учета синхронизации потоков