设计模式 ~ 创建型模式 ~ 原型模式 ~ Prototype Pattern。

设计模式 ~ 创建型模式 ~ 原型模式 ~ Prototype Pattern。



what。

用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型对象相同的新对象。



结构。

原型模式包含如下角色。

  • 抽象原型类。
    规定了具体原型对象必须实现的的 clone(); 方法。

  • 具体原型类。
    实现抽象原型类的 clone(); 方法,ta 是可被复制的对象。

  • 访问类。
    使用具体原型类中的 clone(); 方法来复制新的对象。

接口类图如下。

在这里插入图片描述
原型模式的克隆分为浅克隆深克隆

在这里插入图片描述

  • 浅克隆。
    创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

  • 深克隆。
    创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。



浅克隆(原型模式)。

创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

Java 中的 Object 类中提供了 clone(); 方法来实现浅克隆。

Cloneable 接口是上面的类图中的抽象原型类,而实现了 Cloneable 接口的子实现类就是具体的原型类。代码如下。

package com.example.proto.type.pattern.shallow.clone;

import com.sun.org.slf4j.internal.Logger;
import com.sun.org.slf4j.internal.LoggerFactory;

/**
 * @author geek
 */
public class RealizeType implements Cloneable {

    private static final Logger log
            = LoggerFactory.getLogger(RealizeType.class);

    public RealizeType() {
        System.out.println(" ~ RealizeType ~ RealizeType; ~  ~ {}");
    }

    @Override
    public RealizeType clone() {
        try {
            System.out.println(" ~ RealizeType ~ clone; ~  ~ {}");
            return (RealizeType) super.clone();
        } catch (CloneNotSupportedException e) {
            throw new AssertionError();
        }
    }

}

package com.example.proto.type.pattern.shallow.clone;

/**
 * @author geek
 */
public class Client {

    private static final org.slf4j.Logger log
            = org.slf4j.LoggerFactory.getLogger(Client.class);

    public static void main(String[] args) {

        // 创建一个原型类对象。
        RealizeType realizeType = new RealizeType();

        // 调用 RealizeType 类中的 clone(); 方法进行对象的克隆。
        RealizeType clone = realizeType.clone();
        // 没有执行构造方法。
        log.debug(" ~ Client ~ main; ~ clone == realizeType ~ " + (clone == realizeType) + "\r\n ~ clone ~ " + clone + "\r\n ~ realizeType ~ " + realizeType);

        /*
 ~ RealizeType ~ RealizeType; ~  ~ {}
 ~ RealizeType ~ clone; ~  ~ {}
23:39:37.479 [main] DEBUG com.example.proto.type.pattern.shallow.clone.Client -  ~ Client ~ main; ~ clone == realizeType ~ false
 ~ clone ~ com.example.proto.type.pattern.shallow.clone.RealizeType@724af044
 ~ realizeType ~ com.example.proto.type.pattern.shallow.clone.RealizeType@4678c730
         */
    }

}

eg.

package com.example.proto.type.pattern.use.shallow.clone;

/**
 * 奖状类。
 *
 * @author geek
 */
public class Citation implements Cloneable {

    private String name;

    public String getName() {
        return this.name;
    }

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

    public void show() {
        System.out.println(name + " 同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }

}

package com.example.proto.type.pattern.use.shallow.clone;

/**
 * @author geek
 */
public class CitationTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原型对象。
        Citation citation = new Citation();
        citation.setName("张三");
        // 克隆浅拷贝复制奖状。
        Citation citation1 = citation.clone();
        // 将奖状的名字修改李四。
        citation1.setName("李四");
        citation.show();
        citation1.show();

        /*
        张三 同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
        李四 同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
         */
    }

}

  • 使用场景。

对象的创建非常复杂,可以使用原型模式快捷的创建对象。
性能和安全要求比较高。

package com.example.proto.type.pattern.use.shallow.copy2;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author geek
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String name;

}

package com.example.proto.type.pattern.use.shallow.copy2;

import lombok.Data;

/**
 * 奖状类。
 *
 * @author geek
 */
@Data
public class Citation implements Cloneable {

    private Student student;

    public void show() {
        System.out.println(student.getName() + "同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }

}

package com.example.proto.type.pattern.use.shallow.copy2;

/**
 * @author geek
 */
public class CitationTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原型对象。
        Citation citation = new Citation();
        // 创建张三学生对象。
        Student student1 = new Student("张三");
        citation.setStudent(student1);
        // 克隆 ~ 浅拷贝复制奖状。
        Citation citation1 = citation.clone();
        Student student2 = citation1.getStudent();
        student2.setName("李四");

        citation.show();
        citation1.show();
    }

    // student1 对象和 student2 对象是同一个对象,就会产生将 student1 对象中 name 属性值改为“李四”,
    // 两个 Citation(奖状)对象中显示的都是李四。
    // 这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。
    // 这种情况需要使用深克隆,而进行深克隆需要使用对象流。

    /*
    李四同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
    李四同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
     */

}



深克隆。

创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

package com.geek.prototype.use.deep.copy;

import com.sun.tracing.dtrace.NameAttributes;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @author geek
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String name;

}

package com.example.proto.type.pattern.use.deep;

import lombok.Data;

import java.io.Serializable;

/**
 * 奖状类。
 *
 * @author geek
 */
@Data
public class Citation implements Cloneable, Serializable {

    private Student student;

    public void show() {
        System.out.println(student.getName() + " 同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

//    @Override
//    protected Object clone() throws CloneNotSupportedException {
//        return super.clone();
//    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }

}

package com.geek.prototype.use.deep.copy;

/**
 * @author geek
 */
public class CitationTest {

    public static void main(String[] args) throws CloneNotSupportedException {
        // 创建原型对象。
        Citation citation = new Citation();
        // 创建张三学生对象。
        Student student1 = new Student("张三");
        citation.setStudent(student1);
        // 克隆~ 浅复制奖状。
        Citation c2 = citation.clone();
        Student student2 = c2.getStudent();
        student2.setName("李四");

        citation.show();
        c2.show();
    }

    // student1 对象和 student2 对象是同一个对象,就会产生将 student1 对象中 name 属性值改为“李四”,
    // 两个 Citation(奖状)对象中显示的都是李四。
    // 这就是浅克隆的效果,对具体原型类(Citation)中的引用类型的属性进行引用的复制。
    // 这种情况需要使用深克隆,而进行深克隆需要使用对象流。

    /*
    李四同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
    李四同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
     */

}

  • 实现深克隆。
package com.example.proto.type.pattern.use.deep;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

/**
 * @author geek
 */
public class CitationTest {

    public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
        // 创建原型对象。
        Citation citation = new Citation();
        // 创建张三学生对象。
        Student student = new Student("张三");
        citation.setStudent(student);

        Path path = Paths.get(".\\a.txt");
        // 克隆 ~ 深克隆复制奖状。
        // 创建对象输出流对象。
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(Files.newOutputStream(path));
        // 写对象。
        objectOutputStream.writeObject(citation);
        // 释放资源。
        objectOutputStream.close();

        // 读取对象。
        // 创建对象输入流对象。
        ObjectInputStream objectInputStream = new ObjectInputStream(Files.newInputStream(path));
        // 读取对象。
        Citation citation1 = (Citation) objectInputStream.readObject();
        // 释放资源。
        objectInputStream.close();

        Student student1 = citation1.getStudent();
        student1.setName("李四");

        citation.show();
        citation1.show();
        // Exception in thread "main" java.io.NotSerializableException: com.geek.prototype.use.deep.Citation
        // public class Student implements Serializable {

    }

    /*
    张三 同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
    李四 同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!
     */

}

package com.geek.prototype.use.deep;

import lombok.Data;

import java.io.Serializable;

/**
 * 奖状类。
 *
 * @author geek
 */
@Data
public class Citation implements Cloneable, Serializable {

    private Student student;

    public void show() {
        System.out.println(student.getName() + "同学:在 2020 学年第一学期中表现优秀,被评为三好学生。特发此状!");
    }

    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }

}

package com.geek.prototype.use.deep;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

/**
 * @author geek
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student implements Serializable {

    private String name;

}


package com.geek.prototype.demo00;

import java.util.Date;

/**
 * 浅克隆。
 * 实现一个接口。
 * 重写一个方法 clone(); ~ 直接 return super.clone();。
 */
public class Video implements Cloneable {

    private String name;
    private Date createTime;

    public Video() {
    }

    public Video(String name, Date createTime) {
        this.name = name;
        this.createTime = createTime;
    }

    //     protected native Object clone() throws CloneNotSupportedException;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public String getName() {
        return name;
    }

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

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Video{" +
                "name='" + name + '\'' +
                ", createTime=" + createTime +
                '}';
    }

}

package com.geek.prototype.demo00;

import java.util.Date;

/**
 * 客户端。克隆 video 对象。
 */
public class Bilibili {

    public static void main(String[] args) throws CloneNotSupportedException {
        // 原型对象。
        Video v1 = new Video("狂神说 Java", new Date());
        Video v2 = (Video) v1.clone();
        System.out.println("v1 = " + v1);
        System.out.println("v1.hashCode() = " + v1.hashCode());
        System.out.println("v2 = " + v2);
        System.out.println("v2.hashCode() = " + v2.hashCode());

        // v1 克隆出 v2。
        Video v2Clone = (Video) v1.clone();
        System.out.println("v2Clone = " + v2Clone);
        System.out.println("v2Clone.hashCode() = " + v2Clone.hashCode());

        // v1 = Video{name='狂神说 Java', createTime=Tue Dec 08 14:39:31 CST 2020}
        //v1.hashCode() = 1735600054
        //v2 = Video{name='狂神说 Java', createTime=Tue Dec 08 14:39:31 CST 2020}
        //v2.hashCode() = 21685669
        //v2Clone = Video{name='狂神说 Java', createTime=Tue Dec 08 14:39:31 CST 2020}
        //v2Clone.hashCode() = 2133927002
        //
        //Process finished with exit code 0
    }

}



浅克隆。

package com.geek.prototype.demo00;

import java.util.Date;

/**
 * 浅克隆。
 */
public class Bilibili02 {

    public static void main(String[] args) throws CloneNotSupportedException {

        // 原型对象。
        Date date = new Date();
        Video v1 = new Video("狂神说 Java", date);
        Video v2 = (Video) v1.clone();
        System.out.println("v1 = " + v1);
        System.out.println("v2 = " + v2);

        System.out.println("~ ~ ~ ~ ~ ~ ~");

        date.setTime(123);
        System.out.println("v1 = " + v1);
        System.out.println("v2 = " + v2);

        // v1 v2 同时指向了 date。(浅克隆)。

        // v1 = Video{name='狂神说 Java', createTime=Tue Dec 08 14:42:26 CST 2020}
        //v2 = Video{name='狂神说 Java', createTime=Tue Dec 08 14:42:26 CST 2020}
        //~ ~ ~ ~ ~ ~ ~
        //v1 = Video{name='狂神说 Java', createTime=Thu Jan 01 08:00:00 CST 1970}
        //v2 = Video{name='狂神说 Java', createTime=Thu Jan 01 08:00:00 CST 1970}

        System.out.println("v1.hashCode() = " + v1.hashCode());
        System.out.println("v2.hashCode() = " + v2.hashCode());
        // v1.hashCode() = 1735600054
        //v2.hashCode() = 21685669
        // 哈希值也不一样。
    }

}

在这里插入图片描述



深克隆。

  • 序列化、反序列化。

  • 重写 clone();。

package com.geek.prototype.demo01;

import java.util.Date;

/**
 * 深克隆。
 * 实现一个接口。
 * 重写一个方法 clone();。
 */
public class Video implements Cloneable {

    private String name;
    private Date createTime;

    public Video() {
    }

    public Video(String name, Date createTime) {
        this.name = name;
        this.createTime = createTime;
    }

    // 深克隆。
    //
    //- 序列化、反序列化。
    //
    //- 重写 clone();。

    // 深克隆。
    // 重写一个方法 clone();。
    //     protected native Object clone() throws CloneNotSupportedException;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object clone = super.clone();

        Video obj = (Video) clone;
        // 将对象的属性也进行克隆。
        obj.createTime = (Date) this.createTime.clone();

        return obj;
    }

    public String getName() {
        return name;
    }

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

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }

    @Override
    public String toString() {
        return "Video{" +
                "name='" + name + '\'' +
                ", createTime=" + createTime +
                '}';
    }

}

package com.geek.prototype.demo01;

import java.util.Date;

/**
 * 客户端。克隆。
 */
public class Bilibili02 {

    public static void main(String[] args) throws CloneNotSupportedException {

        // 原型对象。
        Date date = new Date();
        Video v1 = new Video("狂神说 Java", date);
        Video v2 = (Video) v1.clone();
        System.out.println("v1 = " + v1);
        System.out.println("v2 = " + v2);

        date.setTime(123);

        System.out.println("v1 = " + v1);
        System.out.println("v2 = " + v2);

        // v1 = Video{name='狂神说 Java', createTime=Mon Nov 09 12:03:42 CST 2020}
        //v2 = Video{name='狂神说 Java', createTime=Mon Nov 09 12:03:42 CST 2020}
        //v1 = Video{name='狂神说 Java', createTime=Thu Jan 01 08:00:00 CST 1970}
        //v2 = Video{name='狂神说 Java', createTime=Mon Nov 09 12:03:42 CST 2020}

        System.out.println("v1.hashCode() = " + v1.hashCode());
        System.out.println("v2.hashCode() = " + v2.hashCode());
        // v1.hashCode() = 1735600054
        //v2.hashCode() = 21685669
        // 哈希值也不一样。
    }

}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

lyfGeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值