工厂模式
工厂简单来说就是创建产品,根据产品是具体产品还是具体工厂分为简单工厂模式和工厂方法模式,根据工厂的抽象程度可分为工厂方法模式和抽象工厂。该模式用于封装和管理对象的创建,属于创建型模式。
为什么要用工厂模式
- 解耦: 把对象的创建和使用的过程分开
- 降低代码重复: 如果创建某个对象的过程都很复杂,需要一定的代码量,而且很多地方都要用到,那么就会有很多的重复代码。
- 降低维护成本: 由于创建过程都由工厂统一管理,所以发生业务逻辑变化,不需要找到所有需要创建某个对象的地方去逐个修正,只需要在工厂里修改即可,降低维护成本。
1.简单工厂模式
这个模式对对象的创建和管理是最为简单的,因为该模式仅仅简单的对不同类对象的创建进行了一层薄薄的封装。该模式通过项工厂床底类型来指定要创建的对象。其UML类图如下所示:
下面我们使用代码来进行介绍该模式的作用。
Phone类 : 手机接口(AbstractProduct)
public interface Phone{
void make();
}
IPhone类: 制造苹果手机(Product1)
public class IPhone implements Phone{
public IPhone(){
this.make();
}
@Override
publicv void make(){
System.out.println("make IPhone");
}
}
**MiPhone:**制造小米手机(Product2)
public class MiPhone implements Phone{
public MiPhone(){
this.make();
}
@Override
publicv void make(){
System.out.println("make MiPhone");
}
}
**PhoneFactory类:**手机工厂(Factory)
public class PhoneFactory{
public Phone makePhone(String phoneType){
if(phoneType.equals("IPhone")){
return new IPhone();
}else if{
phoneType.equals("MiPhone"){
return new MiPhone();
}
}
}
}
public class Demo{
public static void main(String[] args){
PhoneFactory factory = new PhoneFactory();
Phone iPhone = factory.makePhone("IPhone");
Phone miPhone = factory.makePhone("MiPhone");
}
}
缺点:违背了开放-封闭原则,因为每次需要添加一个功能时,都需要在 if-else语句中去修改代码,添加分支条件。
使用场景
- 需要创建的对象较少。
- 客户端不关心对象的创建过程。
使用反射机制改善简单工厂模式
public class PhoneFactory {
Object makePhone(Class<?> clazz){
Object obj = null;
try {
obj = Class.forName(clazz.getName()).newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return obj;
}
}
工厂方法模式(Factory Method)
和简单工厂模式中工厂负责生产所有产品相比,工厂方法模式将生产具体产品的任务分发给具体的产品工厂,其UML类图如下所示:
也就是定义一个抽象工厂,其定义了产品的生产接口,但不负责具体的产品,将生产任务交给不同的派生类工厂。这样不用通过指定类型来创建对象了。代码如下:
AbstractFactory类: 生产不同产品的工厂的抽象类
public interface AbstractFactory{
Phone makePhone();
}
IPhoneFactory类: 生产IPhone的工厂(ConcreateFactory1)
public class IPhoneFactory implements AbstractFactory{
@Override
public Phone makePhone(){
return new IPhone();
}
}
MiPhoneFactory类: 生产MiPhone的工厂(ConcreateFactory2)
public class MiPhoneFactory implements AbstractFactory{
@Override
public Phone makePhone(){
return new MiPhone();
}
}
public class Demo{
public static void main(String[] args){
AbstractFactory iPhoneFactory = new IPhoneFactory();
AbstractFactory miPhoneFactory = new MiPhoneFactory();
iPhoneFactory.makePhone(); // IPhone
miPhoneFactory.makePhone(); //MiPhone
}
}
缺点: 假如某个具体产品类需要进行一定的修改,很可能需要改变对应的工厂类。当同时需要修改对个产品类时,对工厂类的修改会变得相对麻烦。比如说,没增加一个产品,相应的也要增加一个子工厂,会加大额外的开发量。
适用场景
- 一个类不知道它所需要的对象的类:在工厂方法模式中,客户端不需要知道具体产品类的类名,只需要知道所对应的工厂即可,具体的产品对象由具体工厂类创建;客户端需要知道创建具体产品的工厂类。
- 一个类通过其子类来指定创建哪个对象:在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,利用面向对象的多态性和里氏
- 将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无需关心是哪一个工厂子类创建产品子类,需要时再动态指定,可将具体工厂类的类名存储在配置文件或数据库中。
抽象工厂模式(Abstract Factory)
在工厂方法模式中,我们有一个潜在意识的时候,那就是我们生产的都是同一类产品。抽象工厂模式是工厂方法的进一步深化,在这个模式中的工厂类不单单可以创建一种产品,而是可以创建一组产品。
适用场景
- 和工厂方法一样客户端不需要知道它所创建的对象的类
- 需要一组对象共同完成某种功能时,并且可能存在多组对象完成不同功能的情况。(同属于同一个产品组的产品)
- 系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要改动源代码,不符合开闭原则)
其UML类图如下所示:
此时就会有疑问,这不就是工厂方法吗?抽象工厂的工厂和工厂方法的工厂有什么区别?
抽象工厂是生产一整套有产品的(至少要生产两个产品),这些产品必须相关是有关系或有依赖的,而工厂方法中工厂是生产单一产品的工厂。
代码如下:
PC: 定义PC产品的接口(AbstractPC)
public interface PC{
void make();
}
MiPC类: 定义小米电脑产品(MiPC)
public class MiPC implements PC{
public MiPC(){
this.make();
}
public void make(){
System.out.println("MiPC");
}
}
MAC类: 定义苹果电脑产品(MAC)
public class MAC implements PC{
public MAC(){
this.make();
}
@Override
public void make(){
System.out.println("MAC");
}
}
修改AbstracFactory类: 增加PC产品制造接口
public interface AbstractFactory {
Phone makePhone();
PC makePC();
}
MiFactory类: 增加小米PC的制造(ConcreateFactory1)
public class MiFactory implements AbstractFactory{
@Override
public Phone makePhone(){
return new MiPhone();
}
@Override
public PC makePC(){
return new MIPC();
}
}
MACFactory类: 增加苹果的制造(ConcreateFactory2)
public class AppleFactory implements AbstractFactory{
@Override
public Phone makePhone(){
return new IPhone();
}
@Override
public PC makePC(){
return new MAC();
}
}
演示:
public class Demo {
public static void main(String[] arg) {
AbstractFactory miFactory = new MiFactory();
AbstractFactory appleFactory = new AppleFactory();
miFactory.makePhone(); // MiPhone
miFactory.makePC(); // MIPC
appleFactory.makePhone(); // IPhone
appleFactory.makePC(); // MAC
}
}