设计模式:原型模式

参考
23种设计模式详解(全23种)
23种设计模式(5):原型模式

原型模式

类型:创建型

通过复制现有实例来创建新的实例,无需知道相应类的信息。

关键字:Clone

深拷贝和浅拷贝

浅拷贝:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。

深拷贝:将一个对象复制后,不论是基本数据类型还是引用类型都是重新创建的。

简单来说,就是深拷贝进行了完全彻底的拷贝,而浅拷贝不彻底。
clone明显是深拷贝,clone出来的对象是是不能去影响原型对象

优点

先说优点是因为怕有人觉得为什么不直接new
原因:

  • 使用原型模式创建对象比直接new一个对象在性能上要好的多,因为Object类的clone方法是一个本地方法,它直接操作内存中的二进制流,特别是复制大对象时,性能的差别非常明显。
  • 使用原型模式的另一个好处是简化对象的创建,使得创建对象就像我们在编辑文档时的复制粘贴一样简单。

角色

Client:客户端
Prototype:接口(抽象类),声明具备clone能力,例如java中得Cloneable接口
ConcretePrototype:具体的原型类

UML图

在这里插入图片描述

原型模式的具体实现:一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称,因为Cloneable接口是个空接口,你可以任意定义实现类的方法名,如cloneA或者cloneB,因为此处的重点是super.clone()这句话,super.clone()调用的是Object的clone()方法。

包结构

在这里插入图片描述

原型类

package 原型模式.prototype;

public class PrototypeEmail implements Cloneable{
    @Override
    public PrototypeEmail clone() throws CloneNotSupportedException {
        return (PrototypeEmail) super.clone();
    }
}

具体类

package 原型模式.concretePrototype;

import 原型模式.prototype.PrototypeEmail;

public class Email extends PrototypeEmail {
    public void print(int i){
        System.out.println("制造出了第"+i+"封信");
    }
}

客户端

package 原型模式.client;

import 原型模式.concretePrototype.Email;

public class Client {
    public static void main(String[] args) throws CloneNotSupportedException {
        Email em = new Email();
        for(int i=1;i<=10;i++){
            Email email = (Email)em.clone();
            email.print(i);
        }
    }
}

输出

制造出了第1封信
制造出了第2封信
制造出了第3封信
制造出了第4封信
制造出了第5封信
制造出了第6封信
制造出了第7封信
制造出了第8封信
制造出了第9封信
制造出了第10封信

Process finished with exit code 0

在需要重复地创建相似对象时可以考虑使用原型模式。比如需要在一个循环体内创建对象,假如对象创建过程比较复杂或者循环次数很多的话,使用原型模式不但可以简化创建过程,而且可以使系统的整体性能提高很多。

原型模式的注意事项

1. 使用原型模式复制对象不会调用类的构造方法

因为对象的复制是通过调用Object类的clone方法来完成的,它直接在内存中复制数据。不但构造方法中的代码不会执行,甚至连访问权限都对原型模式无效。

而在单例模式中,只要将构造方法的访问权限设置为private类型,就可以实现单例。但是clone方法直接无视构造方法的权限.

所以,单例模式与原型模式是冲突的,在使用时要特别注意。

2. 深拷贝与浅拷贝。

Object类的clone方法只会拷贝对象中的基本的数据类型,对于数组、容器对象、引用对象等都不会拷贝,这就是浅拷贝。
如果要实现深拷贝,必须将原型模式中的数组、容器对象、引用对象等另行拷贝。

package 原型模式.prototype;

import java.util.ArrayList;

public class PrototypeEmail implements Cloneable{
    private ArrayList arrayList = new ArrayList();
    @Override
    public PrototypeEmail clone() throws CloneNotSupportedException {
        PrototypeEmail pe=(PrototypeEmail)super.clone();
        //这里对引用对象另行拷贝了
        pe.arrayList = (ArrayList)this.arrayList.clone();
        return pe;
    }
}

java提供的大部分的容器类都实现了Cloneable接口
会发生深拷贝的有java中的8种基本类型以及他们的封装类型,另外还有String类型。其余的都是浅拷贝。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值