介绍
在Java
中,我们可以使用new关键字
指定类名来生成类的实例。像这样使用new
来生成实例时,是必须指定类名的。但是,在开发过程中,有时候也会有“在不指定类名的前提下生成实例”
的需求。
应用场景
当某一个类,创建过程过于复杂的时候。
例如,我们假设这里有一个实例,即表示用户在图形编辑器中使用鼠标制作出的图形的实例。想在程序中创建这样的实例是非常困难的。通常,在想生成一个和之前用户通过操作所创建出的实例完全一样的实例的时候,我们会事先将用户通过操作所创建出的实例保存起来,然后在需要时通过复制来生成新的实例。
开始
架构图
样例一
定义产品
public interface IProduct extends Cloneable {
void init();
void use(String str);
IProduct createClone();
}
定义具体产品(下划线、盒子)
@Service
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@Data
public class UnderlinePenProduct implements IProduct {
private char ch ;
@Override
public void init() {
this.ch = '-';
}
@Override
public void use(String str) {
for (int i = 0 ; i < str.length();i++) {
System.out.print(ch);
}
System.out.println();
System.out.println(str);
for (int i = 0 ; i < str.length();i++) {
System.out.print(ch);
}
System.out.println();
}
@Override
public IProduct createClone() {
try {
return (IProduct) super.clone();
} catch (CloneNotSupportedException e) {
log.error("clone error : {}", e.getMessage());
}
return null;
}
}
@Service
@Slf4j
@AllArgsConstructor
@NoArgsConstructor
@Data
public class MessageBoxProduct implements IProduct {
private char ch;
@Override
public void init() {
this.ch = '*';
}
@Override
public void use(String str) {
int n = str.length();
for (int i = 0; i < n + 4; i++) {
System.out.print(ch);
}
System.out.println();
System.out.print(ch + " " + str + " " + ch);
System.out.println();
for (int i = 0; i < n + 4; i++) {
System.out.print(ch);
}
System.out.println();
}
@Override
public IProduct createClone() {
try {
return (IProduct) super.clone();
} catch (CloneNotSupportedException e) {
log.error("clone error : {}", e.getMessage());
}
return null;
}
}
定义产品管理器
@Service
@Slf4j
public class ProductManager implements ApplicationContextAware {
private Map<String, IProduct> productMap = new HashMap<>();
public void register(String productName, IProduct product) {
productMap.put(productName, product);
}
public IProduct cloneProduct(String productName) {
return productMap.get(productName).createClone();
}
public IProduct getParentProduct(String productName) {
return productMap.get(productName);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
//根据接口类型返回相应的所有bean
Map<String, IProduct> beansOfType = applicationContext.getBeansOfType(IProduct.class);
for (Map.Entry<String, IProduct> entry : beansOfType.entrySet()) {
IProduct value = entry.getValue();
value.init();
register(entry.getKey(), value);
}
}
}
测试样例
@Slf4j
@SpringBootTest(classes = PrototypeApplication.class)
public class TestPrototype {
@Resource
private ProductManager productManager;
@Test
public void testPrototype() {
IProduct messageBoxProduct = productManager.getParentProduct("messageBoxProduct");
IProduct messageBoxProductClone = productManager.cloneProduct("messageBoxProduct");
System.out.println(messageBoxProduct == messageBoxProductClone);
messageBoxProductClone.use("hello,world");
messageBoxProduct.use("hello,world");
System.out.println("------------------------------------------------------");
IProduct underlinePenProduct = productManager.getParentProduct("underlinePenProduct");
IProduct underlinePenProductClone = productManager.cloneProduct("underlinePenProduct");
System.out.println(underlinePenProduct == underlinePenProductClone);
underlinePenProductClone.use("hello,world");
underlinePenProduct.use("hello,world");
}
}
总结
优点
- 简化对象的创建过程,通过复制一个已有实例可以提高新实例的创建效率
缺点
- 每一个类都需要配备一个克隆方法