工厂模式
工厂模式是一种常用的创建实例的模式,相当于new
操作。
假设现在有一个Sample
类,如果使用new
创建Sample
实例对象:Sample sample = new Sample();
,但是在实际开发中,有可能在创建实例的时候需要初始化一些工作,比如赋值、查询数据库等。我们可以使用构造函数,这样生成实例就可以写成:Sample sample = new Sample(参数1, 参数2, ...);
。但是,如果创建的Sample
实例不是简单的对某些属性赋值,可能是很复杂的一段逻辑,如果也写入到构造函数中,代码就很难看了。可以考虑把创建实例所需要做的大量初始化工作从Sample
的构造函数中分离出去,这个时候就可以考虑使用Factory
工厂模式创建对象。
工厂模式可以分为三种:简单工厂模式、工厂方法、抽象工厂模式。
1 简单工厂模式
简单工厂模式的结构图如下图所示:
Factory
:工厂类,这是简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类的创建产品类的方法可以被外界直接调用,创建所需的产品对象。IProduct
:抽象产品类,这是简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。Product
:具体产品类,这是简单工厂模式的创建目标
用生产计算机来举例,假设有一个计算机的代工生产商,它目前已经可以代工生产联想计算机了。随着业务的拓展,这个代工生产商还要生产惠普和华硕的计算机。这样就需要用一个单独的类来专门生产计算机,这就用到了简单工厂模式。
第一步,创建抽象产品类
创建一个计算机的抽象产品类,其中有一个抽象方法用于启动计算机,如下所示:
public abstract class Computer {
// 产品的抽象方法,由具体的产品类实现
public abstract void start();
}
第二步,创建具体产品类
接着创建各个品牌的计算机,其都继承了自己的父类Computer
,并实现了父类的start
方法。具体的计算机产品分别是联想、惠普和华硕计算机:
class LenovoComputer extends Computer {
@Override
public void start() {
System.out.println("联想计算机启动");
}
}
class HpComputer extends Computer {
@Override
public void start() {
System.out.println("惠普计算机启动");
}
}
class AsusComputer extends Computer {
@Override
public void start() {
System.out.println("华硕计算机启动");
}
}
第三步,创建工厂类
接下来创建一个工厂类,它提供了一个静态方法createComputer
用来生产计算机。只需要传入想生产的计算机的品牌。就会实例化相应品牌的计算机对象,代码如下所示:
public class ComputerFactory {
public static Computer createComputer(String type) {
Computer computer = null;
switch (type) {
case "lenovo":
computer = new LenovoComputer();
break;
case "hp":
computer = new HpComputer();
break;
case "asus":
computer = new AsusComputer();
break;
}
return computer;
}
}
第四步,客户端调用工厂类
客户端调用工厂类,传入"hp"
生产出惠普计算机并调用该计算机对象的start
方法,如下所示:
class CreateComputer {
public static void main(String[] args) {
ComputerFactory.createComputer("hp").start();
}
}
简单工厂模式:将创建对象的细节封装在一个类(工厂类)中,只需要通过调用工厂类的方法传入特定的参数就能直接创建想要的对象。
优点:使用户根据参数获得对应的类实例,避免了直接实例化类,降低了耦合性。
缺点:可实例化的类型在编译期间已经被确定。如果增加新类型,则需要修改工厂,这违背了开放封闭原则。简单工厂需要知道所有要生成的类型,其当子类过多或者子类层次过多时不适合使用。
开放封闭:软件的实体(类、模块、函数等等)应该可以扩展,但是不可以修改。对扩展是开放的,对更改是封闭的。
简单工厂模式不属于GOF
的23
种经典设计模式,反而是更想一种编程习惯。
2 工厂方法模式
为了解决简单工厂模式中通过工厂创建对象if esle
或者switch
语句过多的问题可以使用工厂方法模式。工厂方法模式的主要原理就是,把每一个要创建的产品对象独立分配一个工厂,提取一个工厂接口出来,独立分配的工厂作为工厂接口的实现类,这样我们在创建工厂——再通过工厂创建对象的过程中,工厂就是唯一确定了的,所以创建的对象也是唯一确定的,不需要再使用过多的判断语句了。
public interface ComputerFactory {
Computer createComputer();
}
public class LenovoComputer implements ComputerFactory{
@Override
public Computer createComputer() {
Computer computer = new LenovoComputer();
...
return computer;
}
}
public class HpComputer implements ComputerFactory{
@Override
public Computer createComputer() {
Computer computer = new HpComputer();
...
return computer;
}
}
public class AsusComputer implements ComputerFactory{
@Override
public Computer createComputer() {
Computer computer = new AsusComputer();
...
return computer;
}
}
class CreateComputer {
public static void main(String[] args) {
ComputerFactory factoryA = new LenovoFactory();
ComputerFactory factoryB = new HpComputer();
ComputerFactory factoryC = new AsusComputer();
LenovoComputer lenovoComputer = factoryA.createComputer();
HpComputer hpComputer = factoryB.createComputer();
AsusComputer asusComputer = factoryC.createComputer();
lenovoComputer.start();
hpComputer.start();
asusComputer.start();
}
2 抽象工厂模式
抽象工厂模式:提供一个接口,用于创建相关对象或依赖对象的家族,而不需要明确指定具体类,通过以来注入来降低耦合;
抽象工厂模式是工厂方法模式的升级版本,它用来创建一组相关或者相互依赖的对象。与工厂方法模式的区别就在于,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式则是针对的多个产品等级结构。 在编程中,通常一个产品结构,表现为一个接口或者抽象类,也就是说,工厂方法模式提供的所有产品都是衍生自同一个接口或抽象类,而抽象工厂模式所提供的产品则是衍生自不同的接口或抽象类。
在抽象工厂模式中,有一个产品族的概念:所谓的产品族,是指位于不同产品等级结构中功能相关联的产品组成的家族。抽象工厂模式所提供的一系列产品就组成一个产品族;而工厂方法提供的一系列产品称为一个等级结构。.
如果工厂的产品全部属于同一个等级结构,则属于工厂方法模式;如果工厂的产品来自多个等级结构,则属于抽象工厂模式。
public interface IFactory {
Computer createComputer();
Phone createPhone();
}
public class HuaWeiFactory implements IFactory {
@Override
public Computer createComputer() {
Computer computer = new HuaWeiComputer();
...
return computer;
}
@Override
public Phone createPhone() {
Phone computer = new HuaWeiPhone();
...
return null;
}
}
public class AppleFactory implements IFactory {
@Override
public Computer createComputer() {
Computer computer = new AppleComputer();
...
return computer;
}
@Override
public Phone createPhone() {
Phone computer = new ApplePhone();
...
return null;
}
}