原型模式

原型模式(Prototype Pattern):通过原型实例指定创建对象的种类,并且通过克隆这些原型来创建新的对象。原型模式是一种创建型模式

 

完成原型模式一般需要3个角色,抽象原型类、具体原型类、客户类

抽象原型类:声明克隆方法的接口、抽象类或具体实现类。是所有具体原型类的公共父类

具体原型类:实现抽象原型类,实现抽象原型类中的克隆方法,并在克隆方法中返回自己的一个克隆对象

客户类:通过原型对象克隆自己创建新的对象

 

实例代码如下

定义抽象原型类,声明克隆方法

package com.design.prototype;

/**
 * 抽象原型类
 */
public interface Prototype {

    //声明克隆方法
    Prototype clone();
}

定义具体原型类,实现抽象原型类,实现克隆方法

package com.design.prototype;

/**
 * 具体原型类
 */
public class ConcretePrototype implements Prototype{

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public Prototype clone() {
        Prototype prototype = new ConcretePrototype();
        ((ConcretePrototype) prototype).setName(this.name);
        return prototype;
    }

    @Override
    public String toString() {
        return "ConcretePrototype{" +
                "name='" + name + '\'' +
                '}' + super.toString();
    }
}

定义客户类,调用测试

package com.design.prototype;

public class TestMain {

    public static void main(String[] args) {
        Prototype prototype = new ConcretePrototype();
        System.out.println(prototype);
       
        //克隆 prototype1 对象
        Prototype prototype1 = prototype.clone();
        System.out.println(prototype1);
    }
}

上述示例代码可以作为原型模式的通用实现,与编程语言特性无关

下边来谈 java 语言实现原型模式

 

java 语言实现原型模式

使用 java 语言实现原型模式很简单。了解 java 语言的人都知道,在 java 语言中所有的类都继承自 java.lang.Object 类,而 Object 类提供了一个 clone()方法,可以将 java 对象进行克隆。因此,使用 java 语言实现原型模式可以不定义抽象原型类,直接使用 Object 类提供的 clone()方法实现对 java 对象的克隆

 

示例代码如下

定义书籍类

注意:要实现克隆的 java 类必须实现 Cloneable 接口,表示这个 java 类支持复制

这里的 clone() 方法直接使用了父类 Object 的 clone()方法

package com.design.prototype.javaprototype;

import java.util.Date;

public class Book implements Cloneable{

    public Book(String bookName, String bookAuthor, Date date){
        this.bookName = bookName;
        this.bookAuthor = bookAuthor;
        this.date = date;
    }

    private String bookName;

    private String bookAuthor;

    private Date date;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookAuthor() {
        return bookAuthor;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

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

    @Override
    public String toString() {
        return "Book{" +
                "bookName='" + bookName + '\'' +
                ", bookAuthor='" + bookAuthor + '\'' +
                ", date=" + date +
                '}'+ super.toString();
    }
}

测试调用

package com.design.prototype.javaprototype;

import java.util.Date;

public class TestMain {

    public static void main(String[] args) throws CloneNotSupportedException {
        Book book = new Book("红楼梦", "曹雪芹", new Date());

        Book book1 = (Book) book.clone();

        System.out.println(book);
        System.out.println(book1);

        System.out.println(book == book1);
        System.out.println(book.getBookName() == book1.getBookName());
    }
}

测试结果如下图

通过打印出的结果可以看出,使用原型模式成功克隆出来 book1 对象

但是,如果仔细观察会发现 book 对象和 book1 对象的 bookName 属性的内存地址值完全相等,通过 debug 进一步分析

发现 book 对象和 book1 对象的属性确实指向了相同的内存地址,这里我们引入两个概念,浅克隆和深克隆

 

浅克隆:若原型对象的成员变量是值类型,则复制一份给克隆对象;若原型对象的成员变量是引用类型,则将引用对象的内存地址复制一份给克隆对象,即原型对象和克隆对象的成员变量都指向相同的内存地址。简单的讲,浅克隆只复制对象本身及其中包含的值类型的成员变量,引用类型的成员对象并没有被复制

 

深克隆:无论原型对象的成员变量是值类型还是引用类型,都复制一份给克隆对象

 

了解了浅克隆和深克隆的概念后,就知道上边的代码其实实现的是浅克隆的原型模式

下边代码演示深克隆的原型模式

这里自定义克隆方法

package com.design.prototype.javaprototype;

import java.io.*;
import java.util.Date;

public class DeepBook implements Serializable {

    public DeepBook(String bookName, String bookAuthor, Date date){
        this.bookName = bookName;
        this.bookAuthor = bookAuthor;
        this.date = date;
    }

    private String bookName;

    private String bookAuthor;

    private Date date;

    public String getBookName() {
        return bookName;
    }

    public void setBookName(String bookName) {
        this.bookName = bookName;
    }

    public String getBookAuthor() {
        return bookAuthor;
    }

    public void setBookAuthor(String bookAuthor) {
        this.bookAuthor = bookAuthor;
    }

    public Date getDate() {
        return date;
    }

    public void setDate(Date date) {
        this.date = date;
    }

    /**
     * 自定义深克隆方法
     * @return
     */
    public DeepBook clone(){
        DeepBook deepBook = null;
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
            objectOutputStream.writeObject(this);

            ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
            ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
            try {
                deepBook = (DeepBook) objectInputStream.readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return deepBook;
    }
}

测试调用

package com.design.prototype.javaprototype;

import java.util.Date;

public class TestMain {

    public static void main(String[] args) throws CloneNotSupportedException {
        DeepBook deepBook = new DeepBook("三国演义","罗贯中", new Date());
        DeepBook deepBook1 = deepBook.clone();

        System.out.println(deepBook.getBookName() == deepBook1.getBookName());
    }
}

控制台打印 false,说明实现了深克隆

 

原型模式总结

优点:创建新的较为复杂的对象时,使用原型模式可以简化创建过程;扩展性好;深克隆方式可以保存对象状态

缺点:因为每个类配备一个克隆方法,所以对已有的类进行改造时,违背了开闭原则;深克隆编写较为复杂的代码比较麻烦

适用场景:创建新的对象成本较大,通过原型模式复制得到可以减少资源占用;构造函数比较复杂;循环体中创建大量对象

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

悟世君子

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

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

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

打赏作者

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

抵扣说明:

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

余额充值