当前位置: 首页 > 后端技术 > Java

23种Java设计模式之原型模式

时间:2023-04-01 23:40:59 Java

23种Java设计模式之原型模式一:介绍设计模式分为三大类:创建型模式,一共五种:工厂方法模式(已经提过)、抽象工厂模式(已经提过)讲过),单例模式(已经讲过),建造者模式(已经讲过),原型模式。结构模式有七种:Adapter模式(已经提到)、Decorator模式、Proxy模式、Appearance模式、Bridge模式、Composition模式、Flyweight模式。行为模式有十一种:策略模式、模板方法模式、观察者模式(已经提到)、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访客模式、中介模式、解释器模式。其实有两种:并发模式和线程池模式。用一张图来整体描述一下:2:Prototype模式使用原型实例来指定要创建的对象的类型,通过复制这些原型来创建新的对象1.关键是需要复制的原型类(Prototype上图中)必须实现“java.lang.Cloneable”接口,然后重写Object类中的clone方法,实现类的复制。Cloneable是一个“标记界面”。所谓标记界面,就是界面中没有内容。标记接口的作用是给所有实现该接口的类一个特殊的标志。使用原型类:/***以原型方式定义一个原型类,并实现Cloneable接口。在java虚拟机中,只能复制实现该接口的类,否则会在运行时抛出CloneNotSupportedException。*/publicclassPrototypeimplementsCloneable{@NonNull@OverrideprotectedPrototypeclone(){Prototypeprototype=null;尝试{原型=(原型)super.clone();}catch(CloneNotSupportedExceptione){e.printStackTrace();}返回原型;}}实现类:publicclassConcretePrototypeextendsPrototype{//名称privateStringname;//年龄privateintage;publicConcretePrototype(Stringname,intage){this.name=name;这个。年龄=年龄;}publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){返回年龄;}publicvoidsetAge(intage){this.age=age;}@OverridepublicStringtoString(){return"Prototype{"+"name='"+name+'\''+",age="+age+'}';}}调用://建立一个真实数据ConcretePrototypeconcretePrototype=newConcretePrototype("Rocky",19);//获取一个拷贝数据ConcretePrototypecloneP=(ConcretePrototype)concretePrototype.clone();System.out.println("具体原型"+具体原型);System.out.println("克隆P"+克隆P);//ResultSystem.out:concretePrototypePrototype{name='Rocky',age=19}System.out:clonePPrototype{name='Rocky',age=19}原型模式是一个比较简单的模式,也很好理解。实现一个接口并重写一个方法就完成了原型模式。在实际应用中,原型模式很少单独出现。经常和其他模式混合,他的原型类Prototype经常被抽象类代替。其实我们也可以把原型类和实现类整合起来。三:浅拷贝和深拷贝原型模式下的拷贝对象分为:“浅拷贝”和“深拷贝”。浅拷贝:浅拷贝是按位复制对象,它创建一个新对象,该对象具有原始对象属性值的精确副本。如果属性是基本类型,则复制基本类型的值;如果属性是内存地址(引用类型),内存地址被复制,所以如果其中一个对象改变了这个地址,就会影响到另一个对象。也就是说,默认的拷贝构造函数只对对象进行浅拷贝(逐个拷贝成员),即只拷贝对象空间,不拷贝资源。注意:浅拷贝影响的引用类型只是复制一个引用类型地址,修改一个对象会影响被复制对象的特性:(1)对于基本数据类型的成员对象,因为基本数据类型是通过value,就是直接给新对象赋属性值。基础类型的副本,其中一个对象修改值而不影响另一个。(2)对于引用类型,比如数组或者类对象,因为引用类型是通过引用传递的,所以浅拷贝只是给成员变量分配内存地址,它们指向同一个内存空间。改变其中一个会影响另一个。如果引用对象没有实现可克隆接口,则不会实现深拷贝。对于引用对象,它是一个浅拷贝。公共类主题{私有字符串名称;公共主题(字符串名称){这个。名字=名字;}publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}@OverridepublicStringtoString(){return"[Subject:"+this.hashCode()+",name:"+name+"]";}}复制了student对象,但是没有复制里面的引用对象,所以是浅拷贝//基本数据类型privateStringname;私人年龄;publicSubjectgetSubject(){返回主题;}publicvoidsetSubject(Subjectsubject){this.subject=subject;}publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}publicintgetAge(){返回年龄;}publicvoidsetAge(intage){this.age=age;}/***重写clone()方法*@return*/@OverridepublicObjectclone(){//浅拷贝try{//直接调用父类的clone()方法returnsuper.clone();}catch(CloneNotSupportedExceptione){返回null;}}@OverridepublicStringtoString(){return"[Student:"+this.hashCode()+",subject:"+subject+",name:"+name+",age:"+age+"]";}}深拷贝:深拷贝不仅会将成员变量的值拷贝为基本数据类型,还会为新对象的引用数据类型的成员变量申请存储空间,并拷贝该成员的对象引用数据类型的变量。这样复制出来的新对象修改引用数据类型的成员变量后,就不怕影响其他复制的对象了。(1)对于基本数据类型的成员对象,由于基本数据类型是按值传递的,所以直接将属性值赋给新的对象。底层类型的副本,其中一个对象修改值而不影响另一个(与浅拷贝相同)。(2)对于引用类型,比如数组或者类对象,深拷贝会创建一个新的对象空间,然后复制里面的内容,使它们指向不同的内存空间。改变一个不会影响另一个。(3)对于多层对象,每个对象都需要实现Cloneable,重写clone()方法,从而实现对象的串行逐层复制。(4)深拷贝比浅拷贝慢且代价高。对于深拷贝,对于Student引用类型的成员变量Subject,需要实现Cloneable,重写clone()方法。公共类Subject实现Cloneable{privateStringname;publicSubject(Stringname){this.name=name;}publicStringgetName(){返回名称;}publicvoidsetName(Stringname){this.name=name;}@OverrideprotectedObjectclone()throwsCloneNotSupportedException{//如果Subject也有引用类型的成员属性,也应该像Student类一样实现returnsuper.clone()。}@OverridepublicStringtoString(){return"[Subject:"+this.hashCode()+",name:"+name+"]";}}Student实现了复制,引用类型Subject也实现了复制。我们通过subject.clone()给studentStudent.subject赋值,所以Copy这个新对象publicclassStudentimplementsCloneable{//referencetypeprivateSubjectsubject;//基本数据类型privateStringname;私人年龄;publicSubjectgetSubject(){返回主题;}publicvoidsetSubject(Subjectsubject){这个。主题=主题;}publicStringgetName(){返回名称;}民众voidsetName(Stringname){this.name=name;}publicintgetAge(){返回年龄;}publicvoidsetAge(intage){this.age=age;}/***重写clone()方法*@return*/@OverridepublicObjectclone(){//深拷贝try{//直接调用父类的clone()方法Studentstudent=(Student)super。克隆();student.subject=(主题)主题。克隆();返校生;}catch(CloneNotSupportedExceptione){返回null;}}@OverridepublicStringtoString(){return"[Student:"+this.hashCode()+",subject:"+subject+",name:"+name+",age:"+age+"]";}}深拷贝后,无论是基本数据类型还是引用类型的成员变量,修改其值都不会相互影响不关心这个世界。