设计模式——创建类——原型模式

2021/5/18 10:57:26

本文主要是介绍设计模式——创建类——原型模式,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

一、原型模式

Specify the kinds of objects to create using a prototypical instance,and create new objects by copying this prototype.
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即 对象.clone()

  • 性能优良,原型模式是在内存二进制流的拷贝,要比直接new一个对象性能好很多,特别是要在一个循环体内产生大量的对象时,原型模式可以更好地体现其优点。

  • 逃避构造函数的约束,这既是它的优点也是缺点,直接在内存中拷贝,构造函数是不会执行的。优点就是减少了约束,缺点也是减少了约束,需要大家在实际应用时考虑。

  • 创建新的对象比较复杂时,可以利用原型模式简化对象的创建过程,同时也能够提高效率

  • 不用重新初始化对象,而是动态地获得对象运行时的状态

  • 如果原始对象发生变化(增加或者减少属性),其它克隆对象的也会发生相应的变化,无需修改代码

  • 在实现深克隆的时候可能需要比较复杂的代码

  • 需要为每一个类配备一个克隆方法,这对全新的类来说不是很难,但对已有的类进行改造时,需要修改其源代码,违背了 ocp 原则,这点请同学们注意.

二、代码

模拟一个发放工资短信通知的例子:
SalaryTemplate.java

@Data
public class SalaryTemplate {
    private String salSubject="工资发放通知";
    private String salContext="本月工资已发放,请您注意查收!";
}

Mail.java

@Data
public class Mail implements Cloneable {

    private String username;
    private String subject;
    private String context;
    private String tail;

    public Mail(SalaryTemplate salaryTemplate) {
        this.subject = salaryTemplate.getSalSubject();
        this.context = salaryTemplate.getSalContext();
    }

    @Override
    public Mail clone() {
        Mail mail = null;
        try {
            mail = (Mail) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        return mail;
    }
}

mail实现了cloneable接口,在类中重写了clone()方法。

Client.java

public class Client {

    private static final int STR_LEN = 6;

    public static void main(String[] args) {
        Mail mail = new Mail(new SalaryTemplate());
        mail.setTail("感谢您对我们工作的支持");
        int i = 0;
        while (i < 6) {
            Mail cloneMail = mail.clone();
            cloneMail.setUsername(getRandomString(STR_LEN));
            sendMail(cloneMail);
            i++;
        }
    }

    private static void sendMail(Mail cloneMail) {
        System.out.println("通知主题:" + cloneMail.getSubject() + " 通知内容: " + "尊敬的" + cloneMail.getUsername() + ", " + cloneMail.getContext() + cloneMail.getTail());
    }

    private static String getRandomString(int length) {
        String source = "abcdefghijklmnopqrskuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
        StringBuffer sb = new StringBuffer();
        Random rand = new Random();
        for (int i = 0; i < length; i++) {
            sb.append(source.charAt(rand.nextInt(source.length())));
        }
        return sb.toString();
    }
}

三、浅拷贝与深拷贝

Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝。

内部的数组和引用对象才不拷贝,其他的原始类型比如int、long、char等都会被拷贝,但是对于String类型,Java就希望你把它认为是基本类型,它是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,在使用的时候就把String当做基本类使用即可。

使用原型模式时,引用的成员变量必须满足两个条件才不会被拷贝:一是类的成员变量,而不是方法内变量;二是必须是一个可变的引用对象,而不是一个原始类型或不可变对象。

实现深拷贝的两种方式:
方式一:使用clone方法:

@Data
public class Thing implements Cloneable {
    private String name;
    private ArrayList<String> stringList;

    @Override
    public Thing clone() {
        Thing cloneThing = null;
        try {
            cloneThing = (Thing) super.clone();
            cloneThing.stringList = (ArrayList<String>) this.stringList.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return cloneThing;
    }
}

方式二:使用序列化(推荐)

@Data
class SerialClone implements Cloneable, Serializable {
    private String name;
    private ArrayList<String> strings;

    @Override
    public Object clone() throws CloneNotSupportedException {
        try {
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream)) {
                objectOutputStream.writeObject(this);
            }
            try (InputStream inputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray())) {
                ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
                return objectInputStream.readObject();
            }
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        SerialClone serialClone=new SerialClone();
        ArrayList<String> arrayList=new ArrayList<>(2);
        arrayList.add("java");
        serialClone.setName("Clone");
        serialClone.setStrings(arrayList);

        System.out.println(serialClone.getStrings());
        SerialClone clone= (SerialClone) serialClone.clone();
        clone.getStrings().add("vue");
        System.out.println(clone.getStrings());
        System.out.println(serialClone.getStrings());
        System.out.println(serialClone==clone);
    }
}


这篇关于设计模式——创建类——原型模式的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程