设计模式---原型模式

学习设计模式之前,可以先了解下六大原则

  • 单一职责原则(类和方法,接口)
  • 开闭原则 (扩展开放,修改关闭)
  • 里氏替换原则(基类和子类之间的关系)
  • 依赖倒置原则(依赖抽象接口,而不是具体对象)
  • 接口隔离原则(接口按照功能细分)
  • 迪米特法则 (类与类之间的亲疏关系)

链接
原型模式

原型模式是一种创建型设计模式,Prototype模式允许一个对象再创建另外一个可定制的对象,根本无需知道任何如何创建的细节,工作原理是:通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建。原型模式包含以下角色:

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

克隆羊 : 多莉

设计模式---原型模式_第1张图片

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

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

Java中的Object类中提供了clone()方法来实现浅克隆。Cloneable接口是Java提供的抽象原型类而实现了Cloneable接口的子实现类就是具体原型类

浅拷贝

【案例】

同一个学校的三好学生奖状除了获奖姓名不同,其他都相同,可以使用原型模式复制出多个三好学生奖状,然后修改奖状上的学生姓名即可
在这里插入图片描述

具体原型类

public class Citation implements Cloneable {
    private String name; //三好学生的姓名

    public String getName(){return name;}
    public void setName(String name) {this.name = name;}
    public void show(){System.out.println(name+"同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状");}
    public Citation clone() throws CloneNotSupportedException {
        return (Citation)super.clone();
    }
}

访问类

public class Test{
    public static void main(String[] args) throws CloneNotSupportedException {
        Citation citation = new Citation();//创建原型对象
        Citation clone = citation.clone();//复制原型对象
        citation.setName("张三");
        clone.setName("李四");
        citation.show();//张三同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状
        clone.show();//李四同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状
    }
}

浅克隆存在的问题

对于浅拷贝来说,具体原型对象的属性只能是基本数据类型和String类型,如果换成其他数据类型会发生什么呢

public class Citation implements Cloneable{
    private Student student;

    public void setStudent(Student student) { 
  		  this.student = student;
    }
    public Student getStudent() {
   		  return student;
    }
    public void show(){
          System.out.println(student.getName()+"同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状");
    }
    protected Citation clone() throws CloneNotSupportedException {
        return (Citation)super.clone();
    }
    
}

class CitationTest{
    public static void main(String[] args) throws Exception {
        Citation citation = new Citation();//创建原型对象
        Student student = new Student();
        student.setName("张三");
        citation.setStudent(student);
        Citation clone = citation.clone();//拷贝原型对象
        clone.getStudent().setName("李四");
        citation.show();//李四同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状
        clone.show();//李四同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状
    }
}

class Student{
    private String name;
    public String getName() {return name;}
    public void setName(String name) {this.name = name;}
}

为什么两个输出都是李四同学?
因为Object类中提供了clone()方法实现的是浅克隆,对于非基本类型属性仍指向原有属性所指向的内存地址,原型类中的student对象和克隆类中的对象是同一个对象,当修改克隆类的student对象时也会修改原型类中的student对象
在这里插入图片描述
深拷贝就能解决以上问题

深拷贝

深拷贝的两种实现方式

  • 重写clone()方法
  • 序列化对象

重写clone()方法

以上面浅拷贝存在问题代码为例,我们只需要重写clone()方法和给Student类实现Cloneable接口并重写clone()方法即可完成深拷贝

//重写clone()方法
public Citation clone() throws CloneNotSupportedException {
	Citation deepClone = (Citation )super.clone();
	deepClone.student = (Student) student.clone();
	return deepClone;
}
//重写clone()方法后Student要实现Cloneable接口
class Student implements Cloneable{
	//其他代码...(和上面一样)
	@Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

序列化对象

以上面浅拷贝存在问题代码为例,在主方法中序列化具体原型对象然后反序列化即可

 public static void main(String[] args) throws Exception {
        Citation citation = new Citation();
        Student student = new Student();
        student.setName("张三");
        citation.setStudent(student);
        /*序列化对象*/
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("b.txt"));//开启对象输出流
        oos.writeObject(citation);//序列化对象
        oos.close();//关闭对象输出流
        /*反序列化对象*/
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("b.txt"));//开启对象输入流
        Citation clone = (Citation ) ois.readObject();//反序列化对象
        ois.close();//关闭对象输入流
        clone.getStudent().setName("李四");
        citation.show();//张三同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状
        clone.show();//李四同学,在2022学年第一学期中表现优异,被评为三好学生,特颁此状
}

//因为要序列化对象所以Student类和Citation类
class Citation implements Cloneable,Serializable{//代码...}
class Student implements Serializable{//代码...}

原型模式的优缺点

  • 优点:
    1、性能提高
    2、逃避构造函数的约束
  • 缺点:
    1、必须实现 Cloneable 接口
    2、需要为每一个类都配置一个 clone 方法

你可能感兴趣的:(设计模式,原型模式,设计模式)