设计模式之原型模式

什么是原型模式

原型模式是用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

为什么要用原型模式

现在有一份纸质版问卷,发问卷的人希望你可以多找一些人填写问卷,你应该怎么做?

答案很简单,找个复印店复印几份嘛:

初步实现

问卷类:

public class Paper {
    private String title;
    private String author;
    private String question;

    public Paper(String title, String author, String question) {
        this.title = title;
        this.author = author;
        this.question = question;
    }

    public String getTitle() { return title; }

    public void setTitle(String title) { this.title = title; }

    public String getAuthor() { return author; }

    public void setAuthor(String author) { this.author = author; }

    public String getQuestion() { return question; }

    public void setQuestion(String question) { this.question = question; }

    @Override
    public String toString() {
        return "Paper{" +
                "title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", question='" + question + '\'' +
                '}';
    }
}

复印机:

public class Copier {
    public static void main(String[] args) throws CloneNotSupportedException {
        Paper paper1 = new Paper("DesignPattern", "Mingyi", "prototype");
        Paper paper2 = new Paper(paper1.getTitle(), paper1.getAuthor(), paper1.getQuestion());
        Paper paper3 = new Paper(paper1.getTitle(), paper1.getAuthor(), paper1.getQuestion());
        Paper paper4 = new Paper(paper1.getTitle(), paper1.getAuthor(), paper1.getQuestion());
        Paper paper5 = new Paper(paper1.getTitle(), paper1.getAuthor(), paper1.getQuestion());
        System.out.println(paper1 + ", hashCode:" + paper1.hashCode()); //1209271652
        System.out.println(paper2 + ", hashCode:" + paper2.hashCode()); //1698156408
        System.out.println(paper3 + ", hashCode:" + paper3.hashCode()); //1740035246
        System.out.println(paper4 + ", hashCode:" + paper4.hashCode()); //884457408
        System.out.println(paper5 + ", hashCode:" + paper5.hashCode()); //913190639
    }
}
分析
  • 确实做到了“复印”的效果。
  • 每一次的“复印”都是让复印机读取原件的相应信息再打印到白纸上的,这是不符合逻辑的。
  • 如果要复印的对象的属性很多、构造起来比较复杂,那么new的时候就会十分麻烦。

为了解决复印麻烦的问题,可以使用原型模式来实现。

使用原型模式实现

  1. 让Paper类实现Cloneable接口(这是一种约定,即使clone()方法在Object类内,但是不实现的话在调用clone()方法时会抛出CloneNotSupportedException异常)
  2. 重写clone()方法

Paper类:

public class Paper implements Cloneable{
    private String title;
    private String author;
    private String question;

    public Paper(String title, String author, String question) {
        this.title = title;
        this.author = author;
        this.question = question;
    }

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

    public String getTitle() { return title; }

    public void setTitle(String title) { this.title = title; }

    public String getAuthor() { return author; }

    public void setAuthor(String author) { this.author = author; }

    public String getQuestion() { return question; }

    public void setQuestion(String question) { this.question = question; }

    @Override
    public String toString() {
        return "Paper{" +
                "title='" + title + '\'' +
                ", author='" + author + '\'' +
                ", question='" + question + '\'' +
                '}';
    }
}

复印机:

public class Copier {
    public static void main(String[] args) throws CloneNotSupportedException {
        Paper paper1 = new Paper("DesignPattern", "Mingyi", "prototype");
        Paper paper2 = (Paper) paper1.clone();
        Paper paper3 = (Paper) paper1.clone();
        Paper paper4 = (Paper) paper1.clone();
        Paper paper5 = (Paper) paper1.clone();
        System.out.println(paper1 + ", hashCode:" + paper1.hashCode()); //1209271652
        System.out.println(paper2 + ", hashCode:" + paper2.hashCode()); //1698156408
        System.out.println(paper3 + ", hashCode:" + paper3.hashCode()); //1740035246
        System.out.println(paper4 + ", hashCode:" + paper4.hashCode()); //884457408
        System.out.println(paper5 + ", hashCode:" + paper5.hashCode()); //913190639
    }
}
分析
  • 实现了复印功能。
  • 复印机复印时只需要“复印”(调用clone()方法)即可,不需要关注原件上的内容究竟是什么(自己new)。
  • 现在的clone是一种浅拷贝方式(因为直接使用的super.clone()方法)。

深拷贝与浅拷贝

浅拷贝:

两个引用,引用了同一块内存空间。

深拷贝:

两个引用,各自引用一块内存空间,这两块内存空间内的值相同。

对比:

  • 对于基本数据类型以及String类型,深拷贝与浅拷贝没有区别。
  • 浅拷贝由于引用了同一块内存空间,一方做出修改时,其他引用也会得到被修改的数据。
  • 深拷贝引用不同的内存空间,每个引用对自己的空间的引用是独立的,互不影响。

深拷贝实现:

假设对于上面的例子,question不是String类型,而是一个Question类型:

Question类:

public class Question implements Cloneable{
    private String question;

    public Question(String question) {
        this.question = question;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException { //需要重写clone方法供Paper类调用
        return super.clone();//由于只有一个String类型的属性,浅拷贝即可
    }

    public String getQuestion() {
        return question;
    }

    public void setQuestion(String question) {
        this.question = question;
    }
}

Paper类:

public class Paper implements Cloneable{
    private String title;
    private String author;
    private Question question;

    public Paper(String title, String author, Question question) {
        this.title = title;
        this.author = author;
        this.question = question;
    }
    
    @Override
    protected Object clone() throws CloneNotSupportedException {
        Paper paper = (Paper) super.clone();
        paper.setQuestion((Question) this.question.clone());//调用question的clone方法,获取一个具有相同属性但内存空间不同的实例。
        return paper;
    }
    
    // ...
} 

这样即实现了Paper的深拷贝。

当然实现深拷贝的方式还有很多,例如可以通过序列化的方式实现,这里就不做赘述了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值