想说的话:
本文所有案例代码
码云:https://gitee.com/helloworld6379/designPattern
Github:Github地址
设计模式概述
1 设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通
用解决方案,设计模式(Design pattern)代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的
一段时间的试验和错误总结出来的。
2 设计模式的本质提高 软件的维护性,通用性和扩展性,并降低软件的复杂度。
3 设计模式并不局限于某种语言,java,php,c++ 都有设计模式.
设计模式类型
设计模式分为三种类型,共 23 种
1 创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
2 结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3 行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter 模式)、状态模式、策略模式、职责链模式(责任链模式)。
不同的资料上对分类和名称略有差别
原型模式
原型模式(Prototype Pattern)是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
这种模式是实现了一个原型接口,该接口用于创建当前对象的克隆。当直接创建对象的代价比较大时,则采用这种模式。例如,一个对象需要在一个高代价的数据库操作之后被创建。我们可以缓存该对象,在下一个请求时返回它的克隆,在需要的时候更新数据库,以此来减少数据库调用。
意图:用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
主要解决:在运行期建立和删除原型。
何时使用: 1、当一个系统应该独立于它的产品创建,构成和表示时。 2、当要实例化的类是在运行时刻指定时,例如,通过动态装载。
如何解决:利用已有的一个原型对象,快速地生成和原型对象一样的实例。
关键代码: 1、实现克隆操作,在 JAVA 继承 Cloneable,重写 clone()
2、原型模式同样用于隔离类对象的使用者和具体类型(易变类)之间的耦合关系,它同样 要求这些"易变类"拥有稳定的接口。
应用实例: 1、细胞分裂。 2、JAVA 中的 Object clone() 方法。
优点: 1、性能提高。 2、逃避构造函数的约束。
缺点: 1、克隆方法需要对类的功能进行通盘考虑,这对于全新的类不是很难,但对于已有的类不一定很容易,特别当一个类引用不支持串行化的间接对象,或者引用含有循环结构的时候。 2、必须实现 Cloneable 接口。
使用场景:
1、资源优化场景。
2、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等。
3、性能和安全要求的场景。
4、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
5、一个对象多个修改者的场景。
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。
7、在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone 的方法创建一个对象,然后由工厂方法提供给调用者。原型模式已经与 Java 融为浑然一体,大家可以随手拿来使用。
注意事项:与通过对一个类进行实例化来构造新对象不同的是,原型模式是通过拷贝一个现有对象生成新对象的。浅拷贝实现 Cloneable,重写,深拷贝是通过实现 Serializable 读取二进制流。
package com.fighting.pattern.prototype.shallowCopy;
/**
* @Description
* @Author LiuXing
* @Date 2020/05/24 23:12
*/
public class Person implements Cloneable{
private String name;
private String birthday;
public Person parent;//是对象, 默认是浅拷贝
public Person(String name, String birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
@Override
protected Object clone(){
Person person = null;
try {
person = (Person)super.clone();
} catch (CloneNotSupportedException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return person;
}
}
/**
* @Description
* @Author LiuXing
* @Date 2020/05/24 23:03
*/
public class CloneTest {
public static void main(String[] args) {
Person person = new Person("刘行","19940628");
person.parent = new Person("xx","xx");
Person person1 = (Person)person.clone();
Person person2 = (Person)person.clone();
Person person3 = (Person)person.clone();
System.out.println("person = " + person + "--- person.parent=" + person.parent.hashCode());
System.out.println("person1 =" + person1 + "--- person1.parent=" + person1.parent.hashCode());
System.out.println("person2 =" + person2 + "--- person2.parent=" + person2.parent.hashCode());
System.out.println("person3 =" + person3 + "--- person3.parent=" + person3.parent.hashCode());
}
}
浅拷贝和深拷贝
深拷贝实现:
package com.fighting.pattern.prototype.deepclone;
import java.io.Serializable;
public class Parent implements Serializable, Cloneable{
private String name;
private String birthday;
public Parent(String name, String birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package com.fighting.pattern.prototype.deepclone;
import java.io.*;
/**
* @Description
* @Author LiuXing
* @Date 2020/05/24 23:12
*/
public class Person implements Serializable, Cloneable {
private String name;
private String birthday;
public Parent parent;
public Person(String name, String birthday) {
this.name = name;
this.birthday = birthday;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getBirthday() {
return birthday;
}
public void setBirthday(String birthday) {
this.birthday = birthday;
}
//深拷贝式1 使用 clone 方法
@Override
protected Object clone() {
Person person = null;
try {
person = (Person) super.clone();
//对引用类型的属性进行克隆
person.parent = (Parent) parent.clone();
} catch (CloneNotSupportedException e) {
System.out.println(e.getMessage());
e.printStackTrace();
}
return person;
}
public Object deepClone() {
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Person person = (Person) ois.readObject();
return person;
} catch (Exception e) {
e.printStackTrace();
System.out.println(e.getMessage());
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
}
}
package com.fighting.pattern.prototype.deepclone;
public class DeepCloneTest {
public static void main(String[] args) {
Person person = new Person("刘行","19940628");
person.parent = new Parent("xx","xx");
//方式1
Person person1 = (Person)person.clone();
Person person2 = (Person)person.clone();
Person person3 = (Person)person.clone();
System.out.println("person = " + person + "--- person.parent=" + person.parent.hashCode());
System.out.println("person1 =" + person1 + "--- person1.parent=" + person1.parent.hashCode());
System.out.println("person2 =" + person2 + "--- person2.parent=" + person2.parent.hashCode());
System.out.println("person3 =" + person3 + "--- person3.parent=" + person3.parent.hashCode());
//方式2
Person person11 = (Person)person.deepClone();
Person person22 = (Person)person.deepClone();
Person person33 = (Person)person.deepClone();
System.out.println("person = " + person + "--- person.parent=" + person.parent.hashCode());
System.out.println("person11 =" + person11 + "--- person11.parent=" + person11.parent.hashCode());
System.out.println("person22 =" + person22 + "--- person22.parent=" + person22.parent.hashCode());
System.out.println("person33 =" + person33 + "--- person33.parent=" + person33.parent.hashCode());
}
}
在Spring中创建bean的时候,多例的情况下,就是使用原型模式创建。
这种clone方法好像并不怎么多用,在js中也有,也是浅拷贝。