二、工厂模式
工厂模式
前言
工厂模式又称为创建模式,它是建对象的一种最佳方式。工厂模式的本质就是用工厂方法代替new操作创建一种实例化对象的方式。
在之前,如果我们想实例化一个对象Simple,一般会想到的方法就是通过构造器来创建Simple simple = new Simple(参数)。但是,如果创建simple实例时所做的初始化工作不是像赋值这样简单的事,可能是很长一段代码,那么每当你需要创建simple这个对象的时候,你都需要写这一段很长的代码。这样我们代码的耦合性就会非常高。所以我们就需要将创建实例的工作和使用使用实例的工作分开,工厂模式会使用工厂方法将创建实例的工作封装起来。这样我们在需要调用对象的时候就不需要关心那些复杂的实例化问题。
简单工厂模式
简单工厂模式中有抽象产品类:用来定义具体产品的共有属性,工厂类则负责生产具体产品。
假设我们需要生产不同品牌的手机
那么我们可以先来定义一个Phone接口
public interface Phone {
String getBrand();
}
然后来创建两个手机品牌:Apple和Huawei
public class Apple implements Phone {
public String getBrand() {
return "apple";
}
}
public class Huawei implements Phone {
public String getBrand() {
return "huawei";
}
}
定义一个工厂来生产手机
public class SimpleFactory {
public static Phone getPhone(String PhoneName){
if ("apple".equals(PhoneName)){
return new Apple();
}else if ("Huawei".equals(PhoneName)){
return new Huawei();
}
return null;
}
}
小结:
从简单工厂中我们可以使用一个静态方法将对象的创建和使用分离开。我们只需要调用方法传递参数就可以获得我们需要的对象。
但我们会发现简单工厂模式存在一系列问题:
- 工厂类集中了所有实例(产品)的创建逻辑,一旦这个工厂不能正常工作,整个系统都会受到影响;
- 违背“开放 - 关闭原则”,一旦添加新产品就不得不修改工厂类的逻辑,这样就会造成工厂逻辑过于复杂。
- 简单工厂模式由于使用了静态工厂方法,静态方法不能被继承和重写,会造成工厂角色无法形成基于继承的等级结构。
为了解决上述的问题,我们又使用了一种新的设计模式:工厂方法模式。
工厂方法模式
工厂方法模式,又称工厂模式、多态工厂模式和虚拟构造器模式,通过定义工厂父类负责定义创建对象的公共接口,而子类则负责生成具体的对象。
将类的实例化(具体产品的创建)延迟到工厂类的子类(具体工厂)中完成,即由子类来决定应该实例化(创建)哪一个类。
下面我们将上面简单工厂模式中生产手机的例子修改为使用工厂方法模式
创建抽象工厂类,定义具体工厂的公共接口
public abstract class PhoneFactory {
Phone getPhone();
}
创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法
public class AppleFactory extends PhoneFactory {
public Phone getPhone() {
return new Apple();
}
}
public class HuaweiFactory extends PhoneFactory {
public Phone getPhone() {
return new Huawei();
}
}
外界通过调用具体工厂类的方法,从而生产出不同手机
小结:
优点
- 更符合开-闭原则,即新增一种产品时,只需要增加相应的具体产品类和相应的工厂子类即可;
- 符合单一职责原则,每个具体工厂类只负责创建对应的产品;
- 不使用静态工厂方法,可以形成基于继承的等级结构;
缺点
-
添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
-
虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
抽象工厂模式
抽象工厂是所有形态的工厂模式中最为抽象和最具一般性的一种形态。抽象工厂是指当有多个抽象角色时使用的一种工厂模式。抽象工厂模式可以向客户端提供一个接口,使客户端在不必指定产品的具体情况下,创建多个产品族中的产品对象。
抽象工厂模式相对于工厂方法模式来说,就是工厂方法模式是针对一个产品系列的,而抽象工厂模式是针对多个产品系列的,即工厂方法模式是一个产品系列一个工厂类,而抽象工厂模式是多个产品系列一个工厂类。
假设我们有两个产品接口Phone和Computer,每一种产品都支持多种系列,比如Apple和Huawei系列。这样每个系列的产品分别是Iphone、Huawei、MacBook、MateBook。为了可以在运行时刻创建一个系列的产品族,我们可以为每个系列的产品族创建一个工厂 AppleFactory和 HuaweiFactory。每个工厂都有两个方法 getPhone 和 getComputer 并返回对应的产品,可以将这两个方法抽象成一个接口 AbstractFactory 。这样在运行时刻我们可以选择创建需要的产品系列。
具体代码:
AbstractFactory:
public abstract class AbstractFactory {
public abstract Phone getPhone();
public abstract Computer getComputer();
}
AppleFactory:
public class AppleFactory extends AbstractFactory {
public Phone getPhone() {
return new Iphone();
}
public Computer getComputer() {
return new MacBook();
}
}
HuaweiFactory:
public class HuaweiFactory extends AbstractFactory {
public Phone getPhone() {
return new Huawei();
}
public Computer getComputer() {
return new MateBook();
}
}
小结:
优点
- 新增一种产品类时,只需要增加相应的具体产品类和相应的工厂子类即可;
- 不使用静态工厂方法,可以形成基于继承的等级结构
- 更符合开-闭原则,新增一种产品类时,只需要增加相应的具体产品类和相应的工厂子类即可
- 符合单一职责原则,每个具体工厂类只负责创建对应的产品
最后总结一下工厂方法模式和抽象工厂模式的区别:
- 工厂方法模式利用继承,抽象工厂模式利用组合
- 工厂方法模式产生一类对象,抽象工厂模式产生一族对象
- 工厂方法模式利用子类创造对象,抽象工厂模式利用接口的实现创造对象