设计模式-建造者模式、原型模式
目录
建造者模式
定义
类图
优缺点
角色
建造者模式和工厂模式比较
使用案例
原型模式
定义
类图
优缺点
应用场景
应用类型
浅克隆
深克隆
建造者模式
定义
将一个复杂的对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。
类图
优缺点
-
优点
-
封装性好,构建和表示分离
-
拓展性好,各个具体的建造者相互独立,有利于系统的解耦
-
客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险
-
-
缺点
-
产品的组成部分必须相同,这限制了其适用范围
-
如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大
-
角色
-
产品角色 (Product) : 它是包含多个组成部件的复杂对象,由具体建造者来创建其各个零部件;
-
抽象建造者 (Builder): 它是一个包含创建产品各个子部件的抽象方法的接口,通常还包含一个返回复杂产品的方法 getResult();
-
具体建造者 (Concrete Builder): 实现Builder 接口,完成复杂产品的各个部件的具体创建方法;
-
指挥者 (Director): 它调用建造者对象中的部件构造与装配方法完成复杂对象的创建,在指挥着中不涉及具体产品的信息;
建造者模式和工厂模式比较
建造者模式和工厂模式的关注点不同,建造者模式注重零部件的组装过程,而工厂方法更注重零部件的创建过程。两者可以结合使用。
使用案例
- Java 中的 StringBuilder
原型模式
定义
原型模式是用于创建重复的对象,同时又能保证性能。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。
类图
优缺点
-
优点
-
Java 自带的原型模式基于内存二进制流的复制,在性能上比直接 new 一个对象更加优良;
-
可以使用深克隆方式保存对象的状态,使用原型模式将对象复制一份,并将其状态保存起来,简化了创建对象的过程,以便在需要的时候使用(列如恢复到历史某一状态),可辅助实现撤销操作;需要为每一个类都配置一个clone 方法
-
-
缺点
-
clone 方法位于类的内部,当对已有类进行改造的时候,需要修改代码,违背了开闭原则;
-
当实现深克隆时,需要编写较为复杂的代码,并且当对象之间存在多重嵌套引用时,为了实现深克隆,每一层对象对应的类都必须支持深克隆,实现起来会比较麻烦。因此,深克隆,浅克隆要运用得当;
-
应用场景
-
对象之间相同或相似,即只是个别的几个属性不同的时候;
-
创建对象成本较大,例如初始化时间长,占用CPU 太多,或者占用网络资源太多等,需要优化资源;
-
创建一个对象需要繁琐的数据准备或访问权限等,需要提高性能或者提高安全性
-
系统中大量使用该类对象,且各个调用者都需要给它的属性重新赋值;
应用类型
浅克隆
-
浅克隆是使用默认的 clone()方法来实现
-
基本数据类型的成员变量,浅克隆会直接进行值传递(复制属性值给新对象)
-
引用数据类型的成员变量,浅克隆会进行引用传递(复制引用值(内存地址)给新对象)
-
在原先Sheep 类基础上实现 Cloneable 接口,重写 clone 方法。
public class Sheep implements Cloneable{
private String name;
private int age;
@Override
protected Object clone() {//克隆该实例,使用默认的clone方法来完成
Sheep sheep = null;
try {
sheep = (Sheep)super.clone();
} catch (Exception e) {
System.out.println(e.getMessage());
}
return sheep;
}
public Sheep(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
深克隆
- 方法1:
- 引用对象也实现 Cloneable 接口
- 对象调用引用对象的clone 方法
- 方法2:
- 实现序列化接口,不必实现Cloneable 接口了
public class Sheep implements Serializable { //实现序列化接口
private String name;
private int age;
public Cow friend;
public Sheep(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Sheep{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public Object deepClone() { //深拷贝
//创建流对象
ByteArrayOutputStream bos = null;
ObjectOutputStream oos = null;
ByteArrayInputStream bis = null;
ObjectInputStream ois = null;
try {
//序列化
bos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(bos);
oos.writeObject(this); //当前这个对象以对象流的方式输出
//反序列化
bis = new ByteArrayInputStream(bos.toByteArray());
ois = new ObjectInputStream(bis);
Sheep sheep = (Sheep) ois.readObject();
return sheep;
} catch (Exception e) {
e.printStackTrace();
return null;
} finally {
//关闭流
try {
bos.close();
oos.close();
bis.close();
ois.close();
} catch (Exception e2) {
System.out.println(e2.getMessage());
}
}
}
}