工厂模式,你还不懂?

139 阅读4分钟

什么是工厂模式(Factory Design Pattern)?

前面讲述了单例模式,今天我们来看看创建型设计模式里的工厂模式。

工厂方法模式,是一种创建型设计模式, 其在父类中提供一个创建对象的方法,允许子类决定实例化对象的类型。

在GoF设计模式中,将工厂模式分为工厂方法和抽象工厂,本文对工厂模式最进一步的划分,划分为简单工厂、工厂方法和抽象工厂。

什么是简单工厂?

什么是简单工厂,我们先看一下这个例子,示例代码如下:

public class ConvertService {

    public <T> T convert(String data, Class<T> type) {
        Convertor convertor = null;
        
        if(int.class.equals(type)) {
            convertor = new String2IntConvertor();
        } else if(long.class.equals(type)) {
            convertor = new String2LongConvertor();
        } else if(...) {
            ...
        } else {
            throw new InvalidTypeException("Convertor is not supported: " + type);
        }
    
        return convertor.doConvert(data);
    }
}

为了让代码可读性更好,更为清晰,我们将功能相对独立的部分抽取出来,示例代码如下:

public class ConvertService {

    public <T> T convert(String data, Class<T> type) {
        Convertor convertor = ConvertorFactory.createConvertor(type);
        
        if(convertor == null) {
             throw new InvalidTypeException("Convertor is not supported: " + type);
        }
    
        return convertor.doConvert(data);
    }
}

public class ConvertorFactory {
    
    public static Convertor createConvertor(Class<T> type) {
        Convertor convertor = null;
        
        if(int.class.equals(type)) {
            convertor = new String2IntConvertor();
        } else if(long.class.equals(type)) {
            convertor = new String2LongConvertor();
        } else if(...) {
            ...
        }
        
        return convertor;
    }
}

工厂的命名一般以“Factory”结尾,但也不是必须的(e.g. Java 的 DateFormat、Calender)。工厂类创建对象一般以“create”开头,也不是肯定的(e.g. getInstance()、createInstance()、newInstance()、valueOf())。这些都可以根据具体场景和习惯命名即可。

上面的代码,如果 if-else 分支很长,将严重影响可读性,我们可以对上述代码进一步优化重构:

public class ConvertService {

    public <T> T convert(String data, Class<T> type) {
        Convertor convertor = ConvertorFactory.createConvertor(type);
        
        if(convertor == null) {
             throw new InvalidTypeException("Convertor is not supported: " + type);
        }
    
        return convertor.doConvert(data);
    }
}

public class ConvertorFactory {

    private static final Map<Class, Convertor> cachedConvertors = new HashMap<>();
    
    static {
        cachedConvertors.put(int.class, new String2IntConvertor());
        cachedConvertors.put(long.class, new String2LongConvertor());
        ...
    }    
    
    public static Convertor createConvertor(Class<T> type) {
        return cachedConvertors.get(type);
    }
}

上面代码实现了简单工厂模式,虽然提高了代码的扩展性,相比原来代码更符合开闭原则,但是同时也增加了类的个数,牺牲了部分代码的可读性。虽然违背开闭原则,但是权衡扩展性和可读性,这样的实现写法在大多数情况下都是没问题的。

什么是工厂方法?

基于上面的例子,我们调整成工厂方法的形式,示例代码如下:

public class ConvertService {

    public <T> T convert(String data, Class<T> type) {
        ConvertorConcreteFactory factory = ConvertorFactory.createConvertor(type);
        
        if(factory == null) {
             throw new InvalidTypeException("Convertor is not supported: " + type);
        }
        
        Convertor convertor = factory.createConvertor();
    
        return convertor.doConvert(data);
    }
}

public class ConvertorFactory {

    private static final Map<Class, ConvertorConcreteFactory> cachedConcreteFactories = new HashMap<>();
    
    static {
        cachedConcreteFactories.put(int.class, new String2IntConvertorConcreteFactory());
        cachedConcreteFactories.put(long.class, new String2LongConvertorConcreteFactory());
        ...
    }    
    
    public static ConvertorConcreteFactory createConvertorConcreteFactory(Class<T> type) {
        return cachedConcreteFactories.get(type);
    }
}

public class String2IntConvertorConcreteFactory implements ConvertorConcreteFactory {
    public Convertor createConvertor() {
        return new String2IntConvertor();
    }
}

public class String2LongConvertorConcreteFactory implements ConvertorConcreteFactory {
    public Convertor createConvertor() {
        return new String2LongConvertor();
    }
}

有人可能会说,工厂方法相比简单工厂方法更复杂了。工厂类再创建一个简单工厂,也就是工厂的工厂,用来创建工厂类对象。如果每个工厂的创建只是简单的 new 就可以完成工厂的创建,功能比较单薄,我们没必要设计成一个独立的类,在这个场景下,简单工厂更合适。但是,如果对象的创建比较复杂,或许还要组合其他类对象,做各种初始化操作,此时应该更推荐使用工厂方法,将复杂的逻辑拆分到各个工厂类中,代码可读性、可扩展性会更好。

什么是抽象工厂?

抽象工厂,并没有简单工厂和工厂方法常用,这里简单了解即可。

在简单工厂和工厂方法,类只有一种,但是在抽象工厂中,类进行了扩充。

我们使用上面的例子进行延伸,现在有需求,String 的风格存在多种,因此需要支持多个转化器:

常规转化器:
String2IntConvertor
String2LongConvertor

风格A转化器
String2IntStyleAConvertor
String2LongStyleAConvertor

...

抽象工厂是怎么解决这样的设计问题呢?示例代码如下:

public interface ConvertorConcreteFactory {
    
    Convertor createConvertor();
    
    StyleAConvertor createStyleAConvertor();
}


public class String2IntConvertorConcreteFactory implements ConvertorConcreteFactory {
    
    public Convertor createConvertor() {
        return new String2IntConvertor();
    }
    
    public StyleAConvertor createStyleAConvertor() {
        return new String2IntStyleAConvertor();
    }
}

public class String2LongConvertorConcreteFactory implements ConvertorConcreteFactory {
    public Convertor createConvertor() {
        return new String2LongConvertor();
    }
    
    public StyleAConvertor createStyleAConvertor() {
        return new String2LongStyleAConvertor();
    }
}

抽象工厂就是针对这种非常特殊的场景而诞生的。单个工厂复杂创建多个不同类型的对象,而不是像简单工厂和工厂方法只创建一种对象,可以比较有效减少工厂类的个数,从而提高代码的可读性。