zoukankan      html  css  js  c++  java
  • 原型模式

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

    原型模式的核心就是一个clone方法,通过该方法进行对象的拷贝,Java提供了一个Cloneable接口来标示这个对象是可拷贝的
    为什么说是“标示”呢?在JDK的帮助中Cloneable是一个方法都没有的,这个接口仅仅只是一个标记作用,在JVM中具有这个标记
    的对象才有可能被拷贝。那么怎么才能将“有可能被拷贝”转换为“可以被拷贝”呢?方法是覆盖clone方法。
    注意,在clone方法上增加一个注解@Override,没有继承任何类为什么可以覆写呢?想想看,在Java中所有类的顶级父类是
    Object类,每个类默认是继承该类的,所以用覆写是非常正确的————即覆写Object类中的clone方法。

    原型模式的优点:
    1.性能优良:原型模式是在内存二进制流的拷贝,要比直接用new实例一个对象性能要好很多,特备是要在一个循环体内产生大量的对象时
    原型模式可以更好的体现其优点。
    2.逃避构造函数的约束:直接在内存中拷贝,构造函数是不会执行的,这即是优点也是缺点。


    原型模式的使用场景:
    1.资源优化场景
    类初始化需要消耗非常多的资源,这个资源包括数据,硬件资源等。
    2.性能和安全要求的场景
    通过new产生一个对象需要繁琐的数据准备或访问权限,则可以使用原型模式
    3.一个对象多个修改者的场景
    一个对象需要提供个其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑用原型模式拷贝多个对象供调用者使用。

    public class AdvTemplate {
        private String advSubject = "XX银行国庆信用卡抽奖活动";
        private String advContext = "国庆抽奖活动能够通知:只要刷卡就送你一百万...";
    
        public String getAdvSubject() {
            return this.advSubject;
        }
    
        public String getAdvContext() {
            return this.advContext;
        }
    }

    public class Mail implements Cloneable { private String receiver; private String subject; private String apellation; private String context; private String tail; public Mail(AdvTemplate advTemplate) { this.context = advTemplate.getAdvContext(); this.subject = advTemplate.getAdvSubject(); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } public String getReceiver() { return receiver; } public void setReceiver(String receiver) { this.receiver = receiver; } public String getSubject() { return subject; } public void setSubject(String subject) { this.subject = subject; } public String getApellation() { return apellation; } public void setApellation(String apellation) { this.apellation = apellation; } public String getContext() { return context; } public void setContext(String context) { this.context = context; } public String getTail() { return tail; } public void setTail(String tail) { this.tail = tail; } }
    public class Client { private static int Max_COUNT = 6; public static void main(String[] args) throws CloneNotSupportedException { Mail mail = new Mail(new AdvTemplate()); for (int i = 0; i < Max_COUNT; i++) { Mail tem = (Mail) mail.clone(); tem.setApellation(i + " 先生/女士"); tem.setReceiver(i + "liaojie@sina.com"); sendMail(tem); } } private static void sendMail(Mail tem) { System.out.println(tem.getApellation()); } }

    利用串行化来做深复制

    把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做“解冻”或者“回鲜(depicking)”过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。

    在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。

    以下为深复制源代码。

    public Object deepClone() 
    { 
    //将对象写到流里 
    ByteArrayOutoutStream bo=new ByteArrayOutputStream(); 
    ObjectOutputStream oo=new ObjectOutputStream(bo); 
    oo.writeObject(this); 
    //从流里读出来 
    ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
    ObjectInputStream oi=new ObjectInputStream(bi); 
    return(oi.readObject()); 
    } 
    这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象可否设成transient,从而将之排除在复制过程之外。上例代码改进如下。
    
    class Professor implements Serializable 
    { 
    String name; 
    int age; 
    Professor(String name,int age) 
    { 
    this.name=name; 
    this.age=age; 
    } 
    } 
    class Student implements Serializable 
    { 
    String name;//常量对象。 
    int age; 
    Professor p;//学生1和学生2的引用值都是一样的。 
    Student(String name,int age,Professor p) 
    { 
    this.name=name; 
    this.age=age; 
    this.p=p; 
    } 
    public Object deepClone() throws IOException, 
    OptionalDataException,ClassNotFoundException 
    { 
    //将对象写到流里 
    ByteArrayOutoutStream bo=new ByteArrayOutputStream(); 
    ObjectOutputStream oo=new ObjectOutputStream(bo); 
    oo.writeObject(this); 
    //从流里读出来 
    ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); 
    ObjectInputStream oi=new ObjectInputStream(bi); 
    return(oi.readObject()); 
    } 
    
    } 
    public static void main(String[] args) 
    { 
    Professor p=new Professor("wangwu",50); 
    Student s1=new Student("zhangsan",18,p); 
    Student s2=(Student)s1.deepClone(); 
    s2.p.name="lisi"; 
    s2.p.age=30; 
    System.out.println("name="+s1.p.name+","+"age="+s1.p.age); //学生1的教授不改变。 
    }
  • 相关阅读:
    ES各种错误解决
    ES 父子文档查询
    logstash jdbc 各种数据库配置
    ruby 疑难点之—— attr_accessor attr_reader attr_writer
    ruby 疑难点之—— yield 和 yield self
    aggregation 详解2(metrics aggregations)
    logstash multiline 把文件处理为单个 event
    aggregation 详解4(pipeline aggregations)
    aggregation 详解3(bucket aggregation)
    C++内存字节对齐规则
  • 原文地址:https://www.cnblogs.com/liaojie970/p/5484227.html
Copyright © 2011-2022 走看看