admin管理员组

文章数量:829187

创建型设计模模式

设计模式

序号内容链接地址
1设计模式七大原则
2创建型设计模式–工厂模式
3创建型设计模式–抽象工厂模式
4创建型设计模式–单例模式
5创建型设计模式–建造者模式
6创建型设计模式—原型模式
7结构型设计模式—代理模式
8结构型设计模式—适配器模式
9结构型设计模式—桥接模式
10结构型设计模式—装饰模式
11结构型设计模式—外观模式
12结构型设计模式—享元模式
13结构型设计模式—组合模式
14行为型设计模式—模板方法模式
15行为型设计模式—策略模式
16行为型设计模式—命令模式
17行为型设计模式—责任链模式
18行为型设计模式—状态模式
19行为型设计模式—观察者模式
20行为型设计模式—中介者模式
21行为型设计模式—迭代器模式
22行为型设计模式—访问者模式
23行为型设计模式—备忘录模式
24行为型设计模式—解释器模式

原型模式

模式的定义与特点

原型模式主要用于对象的复制,用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。在这里,原型实例指定了要创建的对象的种类。用这种方式创建对象非常高效,根本无须知道对象创建的细节。

优点:

  • Java自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良。
  • 可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(例如恢复到历史某一状态),可辅助实现撤销操作。

缺点:

  • 需要为每一个类都配置一个 clone 方法
  • clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则。
  • 当实现深克隆时,需要编写较为复杂的代码,而且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆、浅克隆需要运用得当。
模式的结构

原型模式包含以下主要角色:

  • 抽象原型类:规定了具体原型对象必须实现的接口。
  • 具体原型类:实现抽象原型类的 clone() 方法,它是可被复制的对象。
  • 访问类:使用具体原型类中的 clone() 方法来复制新的对象。

模式的实现

Java 中的 Object 类提供了浅克隆的 clone() 方法,具体原型类只要实现 Cloneable 接口就可实现对象的浅克隆,这里的 Cloneable 接口就是抽象原型类。

/**
* 具体原型类,Cloneable 是抽象原型类
*/
@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@ToString
class BookPrototype implements Cloneable {private String name;private String describe;private String author;@Overrideprotected BookPrototype clone() throws CloneNotSupportedException {return (BookPrototype) super.clone();}}
/**
* 原型模式测试类
*/
public class PrototypePatterns {public static void main(String[] args) throws CloneNotSupportedException {BookPrototype bp = new BookPrototype("设计模式", "详细介绍23种经典设计模式", "A");BookPrototype clone = bp.clone();System.out.println("bp: " + bp.toString());System.out.println("clone: " + clone.toString());System.out.println(bp == clone);}
}

运行结果如下:

注意事项:

  • 原型模式复制对象不会调用类的构造方法。对象的复制是通过调用 clone 方法来完成的,它直接在内存中复制数据,因此不会调用到类的构造方法。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。单例模式中,只要将构造方法的访问权限设置为 privat e型,就可以实现单例。但是 clone 方法直接无视构造方法的权限,所以,单例模式与原型模式是冲突的,在使用时要特别注意。
  • 浅克隆和深克隆:Object 类的 clone 方法只会克隆对象中的基本的数据类型(8种基本数据类型),对于数组、集合、等引用类型都不会克隆,这就是浅克隆。如果要实现深克隆,必须将原型模式中的数组、集合、等引用类型另行克隆。
浅克隆和深克隆

原型模式的克隆分为浅克隆和深克隆:

  • 浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。
  • 深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

我们首先创建一个浅克隆的原型对象并测试结果

/**
* 浅克隆
*/
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class ShallowClone implements Cloneable {private String name;private String[] skills;private BookPrototype bookPrototype;@Overrideprotected ShallowClone clone() {ShallowClone clone = null;try {clone = (ShallowClone)super.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}
}
/**
* 测试浅克隆
*/
public class PrototypePatterns {public static void main(String[] args) throws CloneNotSupportedException {BookPrototype bp = new BookPrototype("设计模式", "详细介绍23种经典设计模式", "A");String[] yasso = new String[]{"浪客之道【被动】", "斩钢闪", "风之障壁", "踏前斩", "狂风绝息斩"};ShallowClone sc = new ShallowClone("yasso", yasso, bp);ShallowClone clone = sc.clone();System.out.println(sc.toString());System.out.println(clone.toString());List<String> catalina = Arrays.asList(new String[]{"贪婪【被动】", "弹射之刃", "伺机待发", "瞬步", "死亡莲华"});String[] skills = sc.getSkills();for (int i = 0; i < skills.length; i++) {skills[i] = catalina.get(i);}System.out.println();System.out.println(sc.toString());System.out.println(clone.toString());}
}

查看运行结果如下:


代码中我们只修改了 sc 实例的 skills 属性,而在打印的信息中可以看到 sc 实例和浅克隆产生的 clone 实例的 skills 属性都被修改了。这正好证明了我们前面浅克隆的定义,即:浅克隆创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址

然后创建一个深克隆的原型对象【属性与浅克隆对象一致】并测试结果

/**
* 深克隆
*/
@Getter
@Setter
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class DeepClone implements Cloneable {private String name;private String[] skills;private BookPrototype bookPrototype;@Overrideprotected DeepClone clone() {DeepClone clone = null;try {clone = (DeepClone)super.clone();clone.skills = this.skills.clone();clone.bookPrototype = this.bookPrototype.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}return clone;}
}
/**
* 测试深克隆
*/
public class PrototypePatterns {public static void main(String[] args) throws CloneNotSupportedException {BookPrototype bp = new BookPrototype("设计模式", "详细介绍23种经典设计模式", "A");String[] yasso = new String[]{"浪客之道【被动】", "斩钢闪", "风之障壁", "踏前斩", "狂风绝息斩"};DeepClone dc = new DeepClone("yasso", yasso, bp);DeepClone clone = dc.clone();System.out.println(dc.toString());System.out.println(clone.toString());List<String> catalina = Arrays.asList(new String[]{"贪婪【被动】", "弹射之刃", "伺机待发", "瞬步", "死亡莲华"});String[] skills = dc.getSkills();for (int i = 0; i < skills.length; i++) {skills[i] = catalina.get(i);}System.out.println();System.out.println(dc.toString());System.out.println(clone.toString());}
}

查看运行结果如下:


代码中我们只修改了 sc 实例的 skills 属性,在打印的信息中可以看到 sc 实例和深克隆产生的 clone 实例中只有 scskills 属性被修改了。这正好证明了我们前面深克隆的定义,即:深克隆创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址

适用场景

原型模式通常适用于以下场景:

  • 对象之间相同或相似,即只是个别的几个属性不同的时候。
  • 创建对象成本较大,例如初始化时间长,占用CPU太多,或者占用网络资源太多等,需要优化资源。
  • 创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性。
  • 系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值。

本文标签: 创建型设计模模式