目录
定义
使用原型实例创建对象实例,然后通过拷贝这些原型来创建新的对象。
在java中主要是通过原型实现Cloneable接口,然后又使用clone方法来复制这个原型实例给客户端,从而实现原型模式的目的。
那么这么做有什么好处呢?创建一个对象的主要就是申请内存+成员变量赋值,在系统中这点开销是可以忽略不记的,所以一般常见也不建议使用原型模式。但是如果在每次创建对象的时候都需要进行加载文件、加解密等操作,这些操作需要耗费大量的时间和资源,而且每次加载的内容都差不多,那么此时我们可以考虑使用原型模式。
实现
下面我们通过一个创建数据库连接的类来体验一下原型模式的实现,首先是有一个数据库的配置文件里面有主从节点的配置,我们要加载相关配置文件,然后通过复制的方式将连接类实例返回给客户端。
主从节点的配置文件 config.properties
master.ip=localhost
master.port=3306
master.username=root
master.password=123456
master.type=mysql
slave.ip=localhost
slave.port=3307
slave.username=root
slave.password=123456
slave.type=mysql
Connection
- 所有数据库连接的父类实现了连接类的主要工作比如加载主配置文件
MasterConnection
& SlaveConnection
- 细化了不同节点的数据库连接并且实现了原型复制
public abstract class Connection implements Cloneable {
protected static Properties properties;
static {
properties = new Properties();
InputStream in = null;
try {
in = new FileInputStream("config.properties");
properties.load(in);
} catch (IOException e) {
e.printStackTrace();
}finally {
try {
assert in != null;
in.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
private String ip;
private String port;
private String username;
private String password;
private String type;
public String getIp() {
return ip;
}
void setIp(String ip) {
this.ip = ip;
}
public String getPort() {
return port;
}
void setPort(String port) {
this.port = port;
}
public String getUsername() {
return username;
}
void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
void setPassword(String password) {
this.password = password;
}
public String getType() {
return type;
}
void setType(String type) {
this.type = type;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class MasterConnection extends Connection{
private static final Connection CONNECTION = new MasterConnection();
static {
CONNECTION.setIp(properties.getProperty("master.ip"));
CONNECTION.setPort(properties.getProperty("master.port"));
CONNECTION.setUsername(properties.getProperty("master.username"));
CONNECTION.setPassword(properties.getProperty("master.password"));
CONNECTION.setType(properties.getProperty("master.type"));
}
public static Connection getConnection() throws CloneNotSupportedException {
return (Connection)CONNECTION.clone();
}
}
public class SlaveConnection extends Connection{
private static final Connection CONNECTION = new SlaveConnection();
static {
CONNECTION.setIp(properties.getProperty("slave.ip"));
CONNECTION.setPort(properties.getProperty("slave.port"));
CONNECTION.setUsername(properties.getProperty("slave.username"));
CONNECTION.setPassword(properties.getProperty("slave.password"));
CONNECTION.setType(properties.getProperty("slave.type"));
}
public static Connection getConnection() throws CloneNotSupportedException {
return (Connection)CONNECTION.clone();
}
}
测试
public class PrototypeTest {
@Test
public void test(){
try {
Connection connection = MasterConnection.getConnection();
System.out.println(connection.getPort());
connection = SlaveConnection.getConnection();
System.out.println(connection.getPort());
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
}
}
=======结果=======
3306
3307
使用场景
- 资源优化场景:创建对象时需要初始化大量的外部资源
- 复杂依赖场景:需要创建的对象A依赖于对象B和对象C,对象B又依赖于对象D.....
- 同一个对象会被多个修改者使用的场景:一个商品可能会给订单、物流、会员多个服务使用修改
- 需要保存原始状态的场景:就比如上面的Connection类,我们需要保存从文件中加载的配置
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。