在软件工程中,创建型模式是一种处理对象创建的设计模式,旨在根据实际情况使用合适的方式来创建对象。这是因为基本的对象创建方式可能会导致设计上的问题,或者增加设计的复杂度。创建型模式的关注点是如何创建对象,其核心思想是要将对象的创建与使用相分离。具体而言,创建型模式分为两种主要类型:对象创建型模式和类创建型模式。
对象创建型模式处理对象的创建,而类创建型模式处理类的创建。其中的一些常见创建型模式:
-
单例(Singleton)模式:确保某个类只能生成一个实例。该实例提供一个全局访问点,供外部获取该对象。单例模式的扩展包括有限多个实例。
-
原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个与原型类似的新实例。
-
工厂方法(Factory Method)模式:定义一个用户创建产品的接口,由子类决定生产什么产品。
-
抽象工厂(Abstract Factory)模式:提供一个创建产品族的接口,每个子类可以生产一系列相关的产品。
-
建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建这些部分,最后构建成复杂对象。
1、工厂方法模式
(1)介绍
工厂方法模式(Factory Method Pattern)是创建型设计模式的一种,它提供了一种创建对象的最佳方式。在工厂方法模式中,对象的创建是通过调用一个工厂方法而不是直接调用构造器来完成的。这个工厂方法可以是指定的接口并由子类实现,或者是类的抽象方法。
定义:
工厂方法模式定义了一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其子类。
涉及到的关键类或接口:
- Product(产品角色):定义工厂方法所创建的对象的接口。
- ConcreteProduct(具体产品角色):实现Product接口的具体类,由具体工厂创建。
- Creator(创建者角色):声明工厂方法,返回一个Product类型的对象。Creator也可以定义一个默认的工厂方法实现。
- ConcreteCreator(具体创建者角色):重写或实现工厂方法,返回一个ConcreteProduct实例。
优点:
- 用户只需要知道具体工厂的名称就可以得到所要的产品,无需知道产品的具体创建过程。
- 在系统增加新的产品时,无需修改现有系统代码,只需添加一个具体产品类和其对应的具体工厂即可,符合开闭原则。
缺点:
- 每次增加一个产品时,都需要增加一个具体类和对象实现工厂,这会使得系统中类的个数成倍增加,增加了系统的复杂度。
适用场景:
- 当一个类不知道它所需要的对象的类时。
- 当一个类希望通过其子类来指定创建对象时。
- 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪个帮助子类是代理者这一信息局部化时。
Java代码示例:
// 抽象产品
public abstract class Product {
public abstract void use();
}
// 具体产品
public class ConcreteProductA extends Product {
@Override
public void use() {
System.out.println("Product A is used.");
}
}
public class ConcreteProductB extends Product {
@Override
public void use() {
System.out.println("Product B is used.");
}
}
// 创建者
public abstract class Creator {
public abstract Product factoryMethod();
}
// 具体创建者
public class ConcreteCreatorA extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductA();
}
}
public class ConcreteCreatorB extends Creator {
@Override
public Product factoryMethod() {
return new ConcreteProductB();
}
}
// 客户端代码
public class Client {
public static void main(String[] args) {
Creator creatorA = new ConcreteCreatorA();
Product productA = creatorA.factoryMethod();
productA.use();
Creator creatorB = new ConcreteCreatorB();
Product productB = creatorB.factoryMethod();
productB.use();
}
}
在这个示例中,Product
是抽象产品,ConcreteProductA
和 ConcreteProductB
是具体产品,Creator
是创建者,ConcreteCreatorA
和 ConcreteCreatorB
是具体创建者。客户端代码通过具体创建者来创建产品实例。
(2)具体例子
package factoryMethod;
/**
* @注释 定义一个人类的统称
*/
public interface Human {
void say();
void cry();
void laugh();
}
定义具体的人种
public class YellowHuman implements Human{
@Override
public void say() {
System.out.println("黄种人会说话");
}
@Override
public void cry() {
System.out.println("黄种人会哭泣");
}
@Override
public void laugh() {
System.out.println("黄种人会大笑");
}
}
public class WhiteHuman implements Human{
@Override
public void say() {
System.out.println("白种人会说话");
}
@Override
public void cry() {
System.out.println("白种人会哭泣");
}
@Override
public void laugh() {
System.out.println("白种人会大笑");
}
}
public class BlackHuman implements Human{
@Override
public void say() {
System.out.println("黑种人会说话");
}
@Override
public void cry() {
System.out.println("黑种人会哭泣");
}
@Override
public void laugh() {
System.out.println("黑种人会大笑");
}
}
定义一个工厂
package factoryMethod;
import java.util.HashMap;
/**
* @注释 定义一个工厂类
*/
public class HumanFactory {
// 作为对象实例的缓存
private static HashMap<String, Human> cacheMap = new HashMap<>();
public static Human createHuman(Class c){
Human human = null;
try{
if(cacheMap.containsKey(c.getSimpleName())){
// 如果缓存中存在,就不需要通过反射获取
human = cacheMap.get(c.getSimpleName());
}else{
// 通过反射获取对象的实例
human = (Human) Class.forName(c.getName()).newInstance();
cacheMap.put(c.getSimpleName(), human);
}
}catch (InstantiationException e)