`
jackyhongvip
  • 浏览: 159219 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

设计模式之不变模式(Immutable Pattern)分析

    博客分类:
  • j2se
 
阅读更多

主要介绍编写不变类的主意事项:

归纳一下设计不变类的 5 条规则:

1. 不提供任何修改对象的方法。

2. 保证没有任何一个方法会被覆盖。

3. 所有的域都是 final 的。

4. 所有的域都是 private 的。

5. 如果不变类内部包括可变的子对象,保证它绝对不会被其他代码获取引用。

 

实例:

/**
* @author Peter Wei
*
*/
public class User {

private String name;

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

}

/**
* 弱不变模式
*
* @author Peter Wei
*
*/
public class WeakImmutable {

// 属性私有,满足条件2
private int state;
// 属性私有,满足条件2
private User user;

private Integer age;

public WeakImmutable(int state, User user, Integer age) {
this.state = state;
this.user = user;
this.age = age;
}

public int getState() {
return this.state;
}

public User getUser() {
return this.user;
}

public Integer getAge() {
return this.age;
}

public void setState() {
// 对象没有任何方法修改对象的状态,满足条件1
// do nothing.
}

public static void main(String[] args) {
int state = 0;
User u = new User();
Integer age = 100;
u.setName("yes");
WeakImmutable weak = new WeakImmutable(state, u, age);
System.out.println("原始值:" + weak.getState() + ","
+ weak.getUser().getName() + "," + weak.getAge());
// 修改引用后
state = 5;
// User由于是可变对象引用,所以有影响
u.setName("no");
age = 200;
System.out.println("修改引用后:" + weak.getState() + ","
+ weak.getUser().getName() + "," + weak.getAge());
}
}结果:可以看到user的名字会改变。
原始值:0,yes,100
修改引用后:0,no,100

我们再引伸一个不可变类的例子:
在时间截止时,我们需要一一检查队列成员是不是vip,如果是可以去USA.假设是多线程环境,并且users数组是多线程共享,那么另外的线程通过users去修改users[n],这时就会把users[n]绕过时间检查而去USA.

Java代码 复制代码 收藏代码
  1. /**
  2. * 不变模式之clone
  3. *
  4. * @author Peter Wei
  5. *
  6. */
  7. publicclass WeakImmutableClone {
  8. publicstaticvoid main(String[] args) {
  9. User[] users = new User[3];
  10. users[0] = new User();
  11. users[0].setName("peterwei");
  12. users[1] = new User();
  13. users[1].setName("Tomssssss");
  14. users[2] = new User();
  15. users[2].setName("peterwei88");
  16. time4Check();
  17. /*
  18. * 时间到,我们需要一一检查队列成员是不是vip,如果是可以去USA.假设是多线程环境,并且users数组是多线程共享,
  19. * 那么另外的线程通过users去修改users[n],这时就会把users[n]绕过时间检查而去USA.
  20. */
  21. goUSA(users);
  22. }
  23. publicstaticvoid goUSA(User[] users) {
  24. // User[] tmp = new User[users.length];
  25. // System.arraycopy(users, 0, tmp, 0, users.length);
  26. for (User u : users) {
  27. if (checkVip(u)) {
  28. System.out.println("You can go!");
  29. } else {
  30. System.out.println("go away!");
  31. }
  32. }
  33. }
  34. publicstaticboolean checkVip(User user) {
  35. if (user.getName().startsWith("peterwei")) {
  36. returntrue;
  37. }
  38. returnfalse;
  39. }
  40. publicstaticvoid time4Check() {
  41. // 假设时间期限到,要检查上万人以上的队列。
  42. }
  43. }
/**
 * 不变模式之clone
 * 
 * @author Peter Wei
 * 
 */
public class WeakImmutableClone {

	public static void main(String[] args) {

		User[] users = new User[3];
		users[0] = new User();
		users[0].setName("peterwei");
		users[1] = new User();
		users[1].setName("Tomssssss");
		users[2] = new User();
		users[2].setName("peterwei88");

		time4Check();
		/*
		 * 时间到,我们需要一一检查队列成员是不是vip,如果是可以去USA.假设是多线程环境,并且users数组是多线程共享,
		 * 那么另外的线程通过users去修改users[n],这时就会把users[n]绕过时间检查而去USA.
		 */

		goUSA(users);

	}

	public static void goUSA(User[] users) {

		// User[] tmp = new User[users.length];
		// System.arraycopy(users, 0, tmp, 0, users.length);

		for (User u : users) {
			if (checkVip(u)) {
				System.out.println("You can go!");
			} else {
				System.out.println("go away!");
			}

		}
	}

	public static boolean checkVip(User user) {
		if (user.getName().startsWith("peterwei")) {
			return true;
		}
		return false;
	}

	public static void time4Check() {
		// 假设时间期限到,要检查上万人以上的队列。
	}
}


解决方法:
在事务处理及数据大批量入库的多线程环境中,应该也会有类似的问题。所以对于这样的传入参数及上例中的不变对象引用可变对象,我们可以将其在相关构造函数及方法中复制为本地变量(数组),及使用它的深度clone,阻止相关数据与外部线程的联系。

Java代码 复制代码 收藏代码
  1. publicstaticvoid goUSA(User[] users) {
  2. User[] tmp = new User[users.length];
  3. System.arraycopy(users, 0, tmp, 0, users.length);
  4. for (User u : tmp) {
  5. if (checkVip(u)) {
  6. System.out.println("You can go!");
  7. } else {
  8. System.out.println("go away!");
  9. }
  10. }
  11. }
	public static void goUSA(User[] users) {

		User[] tmp = new User[users.length];
		System.arraycopy(users, 0, tmp, 0, users.length);

		for (User u : tmp) {
			if (checkVip(u)) {
				System.out.println("You can go!");
			} else {
				System.out.println("go away!");
			}

		}
	}


强不变模式:

一个类的实例的状态不会改变,同时它的子类的实例也具有不可变化的状态。这样的类符合强不变模式。要实现强不变模式,一个类必须首先满足弱不变模式所要求的所有条件,并且还要满足下面条件之一:
第一,所考虑的类所有的方法都应当是final,这样这个类的子类不能够置换掉此类的方法。
第二,这个类本身就是final的,那么这个类就不可能会有子类,从而也就不可能有被子类修改的问题。

不变模式在Java中的应用
如String类

Java代码 复制代码 收藏代码
  1. String a = "123" ;
  2. String a1 = "123" ;
  3. String a2 = "123" ;
  4. String a3 = "1234" ;
		String a = "123" ;
		String a1 = "123" ;
		String a2 = "123" ;
		String a3 = "1234" ;


java虚拟机只会创建一个字符串实例,a,a1,a2对象共享一个值。遇到不同的字符串,java虚拟机会再创建一个String对象,如a3。如果程序所处理的字串有频繁的内容变化,就不宜使用String类型,而应当使用StringBuffer类型,如果需要对字串做大量的循环查询,也不宜使用String类型,应当考虑使用byte或char数组.

 

分享到:
评论

相关推荐

    java多线程设计模式详解(PDF及源码)

    本书浅显易懂的介绍了JAVA线程相关的设计模式,通过程序范例和UML图示来一一解说,书中代码的重要部分加了标注以使读者更加容易理解,再加上图文并茂,对于初学者还是程序设计高手来说,这都是一本学习和认识JAVA...

    源码:阎宏设计模式光盘

    com.javapatterns.immutable 不变模式 com.javapatterns.interfaces Java接口 com.javapatterns.interpreter 解释器模式 com.javapatterns.isp 接口隔离原则 com.javapatterns.iterator 迭代子模式 ...

    Immutable详解及React中实践.pdf

    Immutable 的实现原理是 Persistent Data Structure(持久化数据结构),即使用旧数据创建新数据时,要保证旧数据同时可用且不变。同时,Immutable 使用了 StructuralSharing(结构共享),即如果对象树中一个节点...

    技术分享之immutable.js.pptx

    简单介绍Immutable.js的一个ppt,主要用于技术分享,内容为imuutabe常用的数据类型和常用的基础api,还有immutable的原理、优缺点的分析。

    Android设计模式原型模式应用简单Demo

    原型模式(Prototype Pattern)作为GOF设计模式之一,是一种创建型模式,它提供了一种复制已有对象而不必知道其具体类别的方法。在这个“Android设计模式原型模式应用简单Demo”中,我们将探讨如何在Android环境中...

    82丨开源实战三(中):剖析GoogleGuava中用到的几种设计模式1

    在本篇中,我们将深入探讨Guava中使用的三种设计模式:Builder模式、Wrapper模式以及Immutable模式。 ### 1. Builder模式 Builder模式在Guava中主要用来构建复杂对象,例如在`...

    前端开源库-immutable-core

    Immutable.js 是一个著名的实现不可变数据结构的库,但“immutable-core”则更专注于提供核心的不变数据操作功能。 **二、为什么使用Immutable-core?** 1. **性能提升**:通过减少不必要的对象复制,immutable-...

    Docker and Immutable Infrastructure

    1.Overview of Docker the company and growth 2.Overview of Docker the latest stuff (DCUS announcements) & CaaS;...4.Docker and Immutable infrastructure/Microservices working together.

    前端开源库-immutable-ai

    2. **提高性能**:通过利用共享数据结构(如尾递归优化和 Map 的键值对引用不变性),Immutable.js 可以实现高效的浅层拷贝和对比,减少不必要的对象复制。 3. **时间旅行与状态管理**:在 Redux 或其他状态管理库...

    druid 源码分析 逐层详解

    分析源码时,我们可以看到各种设计模式的影子,理解这些模式是如何帮助开发者构建高效、可维护的代码库。 依赖注入也是Druid源码分析中不可或缺的一个知识点。在Druid的实现中,我们看到了Guice这一依赖注入框架的...

    java多线程设计模式 (PDF中文版, 附源码)

    目录: 漫谈UML Introduction 1 Java语言的线程 Introduction 2 多线程...总结 多线程程序设计的模式语言 附录A 练习问题的解答 附录B Java的内存模型 附录C Java线程的优先级 附录D 线程相关的主要API 附录E 参考文献

    Mastering Immutable.js epub

    Mastering Immutable.js 英文epub 本资源转载自网络,如有侵权,请联系上传者或csdn删除 本资源转载自网络,如有侵权,请联系上传者或csdn删除

    ImmutableArray原型方法Per方法包的集合

    通常,阅读源码可以帮助开发者了解如何在自己的项目中实现类似的功能,或者学习作者的编程技巧和设计模式。 总结来说,`ImmutableArray`的`Per`方法是用于生成不可变数组的所有可能排列的工具,这在需要探索所有...

    immutabilityutil一个开源immutabledata的轮子

    3. `merge`:合并两个或更多的对象,返回一个新的合并后的对象,原对象保持不变。 4. `push`、`pop`、`unshift`、`shift`:这些方法用于操作数组,就像它们在原生JavaScript数组上那样,但它们会返回一个新的数组,...

    21-C-ImmutableObject-Code.zip

    在编程领域,不可变对象(Immutable Object)是一种重要的设计模式,尤其在多线程和并发环境中,它提供了安全性和性能优化。在这个初学者教程中,我们将深入探讨C#中的不可变对象,包括“内部不变性”和“观察不变性...

    Android代码-kotlinx.collections.immutable

    Immutable Collections Library for Kotlin Immutable collection interfaces and implementation prototypes for Kotlin. For further details see the proposal. Prototype implementation is based on ...

    Node.js-immutable-Javascript不可变的持久化数据集合

    `immutable.js`的设计深受函数式编程理念影响,它鼓励使用纯函数,即没有副作用、仅依赖于输入参数的函数。通过这种方式,可以避免共享状态和并发问题,提高代码的可测试性和可维护性。 **性能优化** 虽然创建新的...

    kotlinx.collections.immutable,Kotlin的不可变集合原型.zip

    `kotlinx.collections.immutable`库中的实现通常基于“持久化数据结构”(Persistent Data Structure),这是一种特殊的数据结构设计,即使在进行修改操作时也能保持旧版本的引用。这种设计保证了高效性能,因为...

    前端开源库-redux-immutable

    本文将深入探讨“前端开源库-redux-immutable”,这是一个专为Redux设计的库,旨在解决在处理状态时的不变性问题。 Redux 是一个流行的状态管理库,它在JavaScript应用中扮演着中央数据仓库的角色,负责存储所有的...

Global site tag (gtag.js) - Google Analytics