设计模式--原型模式和建造者模式
原型模式
原型模式(Prototype Pattern)是指原型实例指定创建对象的种类,并且通过拷贝这些这些原型创建新的对象,属于创建型模式。(对不通过new关键字,而是通过对象拷贝来实现创建对象的模式称为原型模式)。
原型模式的核心在于拷贝原型对象。以系统中已经存在的一个对象为原型,直接基于内存二进制流进行拷贝,无需再经历耗时的对象初始化过程(不调用构造函数)。
原型模式适用以下场景:
- 类初始化消耗资源比较多
- new产生的一个对象需要非常繁琐的过程
- 构造函数比较复杂
- 循环体中产生大量的对象
一个标准的原型模式代码:
interface IPrototype<T>{
T clone();
}
class ConcretePrototype implements IPrototype{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
ConcretePrototype concretePrototype = new ConcretePrototype();
concretePrototype.setAge(this.age);
concretePrototype.setName(this.name);
return concretePrototype;
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
public class Test {
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("Tom");
System.out.println(prototype);
ConcretePrototype cloneType = prototype.clone();
System.out.println(cloneType);
}
}
上面的复制过程是我们自己完成的,另外,JDK已经帮我们实现了一个现成的API,我们只需要实现Cloneable接口即可。
class ConcretePrototype implements Cloneable{
private int age;
private String name;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}
然而,复制后的克隆对象是的成员复制的不是值,而是引用的地址。如果我们修改任意一个对象中的属性值,prototype和cloneType的属性值都会改变。这就是我们常说的浅克隆。只是完整复制了值数据类型,没有赋值引用对象(所有的引用对象仍然指向原来的对象)。
使用序列化实现深度克隆:
class ConcretePrototype implements Cloneable, Serializable {
private int age;
private String name;
private List<String> hobbies;
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public List<String> getHobbies() {
return hobbies;
}
public void setHobbies(List<String> hobbies) {
this.hobbies = hobbies;
}
@Override
public ConcretePrototype clone() {
try {
return (ConcretePrototype) super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
public ConcretePrototype deepClone(){
try{
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return (ConcretePrototype) ois.readObject();
}catch (Exception e){
e.printStackTrace();
return null;
}
}
@Override
public String toString() {
return "ConcretePrototype{" +
"age=" + age +
", name='" + name + '\'' +
", hobbies=" + hobbies +
'}';
}
}
public class Test {
public static void main(String[] args) {
ConcretePrototype prototype = new ConcretePrototype();
prototype.setAge(18);
prototype.setName("Tom");
List<String> hobbies = new ArrayList<>();
hobbies.add("Math");
hobbies.add("baseball");
prototype.setHobbies(hobbies);
System.out.println(prototype);
ConcretePrototype cloneType = prototype.deepClone();
System.out.println(cloneType);
System.out.println(prototype.getHobbies());
System.out.println(cloneType.getHobbies());
System.out.println(prototype.getHobbies() == cloneType.getHobbies());
}
}
克隆破坏单例模式
如果我们克隆的目标对象是单例对象,那么深克隆就会破坏单例。为了防止克隆破坏单例,只要禁止深克隆就行。
一种是不实现Cloneable接口,重新clone方法,在clone方法中返回单例对象即可。
原型模式的优缺点:
优点:
1、性能优良,Java自带的原型模式是基于内存二进制流的拷贝,比直接new一个对象性能提升许多。
2、可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份并将其保存起来,简化了创建对象的过程。
缺点:
1、需要为每一个类配置一个克隆方法。
2、克隆方法位于类的内部,当对已有的类进行改造的时候,需要修改代码,违反了开闭原则。
3、实现深度克隆需要编写较为复杂的代码。
建造者模式
建造者模式(Builder Pattern)是将一个复杂对象的构建过程与它的表示分离,使得同样的构建过程可以创建不同的表示,属于创建型模式。建造者模式适用于创建对象需要很多步骤,但步骤的顺序不一定固定。如果一个对象有非常复杂的内部结构(很多属性),可以将复杂对象的创建和使用进行分离。
建造者模式的基本写法:
import lombok.Data;
@Data
class Course{
private String name;
private String ppt;
private String video;
}
class CourseBuilder{
private Course course = new Course();
public void addName(String name){
course.setName(name);
}
public void addPpt(String ppt){
course.setPpt(ppt);
}
public void addVideo(String video){
course.setVideo(video);
}
public Course build(){
return this.course;
}
}
public class Test {
public static void main(String[] args) {
CourseBuilder builder = new CourseBuilder();
builder.addName("设计模式");
builder.addPpt("【ppt】");
builder.addVideo("【视频】");
Course course = builder.build();
System.out.println(course);
}
}
建造者模式的链式写法:
import lombok.Data;
class CourseBuilder{
@Data
public class Course{
private String name;
private String ppt;
private String video;
}
private Course course = new Course();
public CourseBuilder addName(String name){
course.setName(name);
return this;
}
public CourseBuilder addPpt(String ppt){
course.setPpt(ppt);
return this;
}
public CourseBuilder addVideo(String video){
course.setVideo(video);
return this;
}
public Course build(){
return this.course;
}
}
public class Test {
public static void main(String[] args) {
CourseBuilder builder = new CourseBuilder()
.addName("设计模式")
.addPpt("【ppt】")
.addVideo("【视频】");
System.out.println(builder.build());
}
}
在JDK中StringBuilder,它提供append()方法,就是应用了建造者模式。
建造者模式的优缺点:
优点:
1、封装性好,创建和使用分离;
2、扩展性好,建造类之间独立,一定程度上解耦。
缺点:
1、产生多余的Builder对象
2、产品内部发生变化,建造者都要修改,成本比较大。
建造者模式和工厂模式的区别:
1、建造者模式更加注重方法的调用顺序,工厂模式注重于创建对象。
2、创建对象的力度不同,建造者模式创建复杂的对象,由各种复杂的部件组成,工厂模式创建出来的都一样。
3、关注点不一样,工厂模式只需要把对象创建出来就可以了,而建造者模式不仅要创建这个对象,还要知道这个对象由哪些部件组成。
4、建造者模式根据建造过程中的顺序不一样,最终的对象部件组成也不一样。
原文地址:https://blog.csdn.net/qq_38619449/article/details/136235137
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!