【设计模式系列1】深入分析简单工厂,工厂方法和抽象工厂三种设计模式

三大工厂设计模式对比

  • 设计模式系列总览
  • 前言
  • 简单工厂模式(Simple Factory Pattern)
    • 简单工厂示例
    • 简单工厂模式适用场景
    • 简单工厂模式缺点
  • 工厂方法模式(Fatory Method Pattern)
    • 工厂方法模式适用场景
    • 工厂方法模式缺点
  • 抽象工厂模式(Abstract Factory Pattern)
    • 抽象工厂示例
    • 抽象工厂使用场景
    • 抽象工厂缺点
  • 总结

设计模式系列总览

设计模式 飞机票
三大工厂模式 登机入口
策略模式 登机入口
委派模式 登机入口
模板方法模式 登机入口
观察者模式 登机入口
单例模式 登机入口
原型模式 登机入口
代理模式 登机入口
装饰者模式 登机入口
适配器模式 登机入口
建造者模式 登机入口
责任链模式 登机入口
享元模式 登机入口
组合模式 登机入口
门面模式 登机入口
桥接模式 登机入口
中介者模式 登机入口
迭代器模式 登机入口
状态模式 登机入口
解释器模式 登机入口
备忘录模式 登机入口
命令模式 登机入口
访问者模式 登机入口
软件设计7大原则和设计模式总结 登机入口

前言

设计模式系列文章将会介绍全部的GoF23种设计模式,希望能和大家一起交流学习。
本文会介绍工厂模式的三种写法

简单工厂模式(Simple Factory Pattern)

指的是由一个工厂对象来决定创建具体的产品实例,简单工厂模式并不属于GoF23种设计模式之一,但是我们在平常开发中也运用的非常广泛。

简单工厂示例

创建一个产品接口:

package com.zwx.design.pattern.factory.simple;

public interface IProduct {
     
    void grow();
}

创建产品苹果类:

package com.zwx.design.pattern.factory.simple;

public class Apple implements IProduct {
     
    @Override
    public void grow() {
     
        System.out.println("种植苹果");
    }
}

创建产品桔子类:

package com.zwx.design.pattern.factory.simple;

public class Orange implements IProduct {
     
    @Override
    public void grow() {
     
        System.out.println("种植桔子");
    }
}

创建一个简单工厂类,里面封装了创建具体产品对象的方法

package com.zwx.design.pattern.factory.simple;

public class SimpleFactory {
     
    public IProduct createProduct(String productType){
     
        if("apple".equals(productType)){
     
            return new Apple();
        }else if("orange".equals(productType)){
     
            return new Orange();
        }
        return null;
    }
}

最后让我们来新建一个测试类测试一下

package com.zwx.design.pattern.factory.simple;

public class TestSimpleFactory {
     
    public static void main(String[] args) {
     
        SimpleFactory factory = new SimpleFactory();
        IProduct apple = factory.createProduct("apple");
        apple.grow();//输出:种植苹果

        IProduct orange = factory.createProduct("orange");
        orange.grow();//输出:种植桔子
    }
}

上面就基本上实现了一个简单工厂模式,但是我们发现,假如我们要增加一个产品西瓜,那么我们就需要去修改创建工厂实现了类,这就违背了软件设计的开闭原则,所以,我们可以对SimpleFactory类利用反射进行改进。
改进后的工厂实现类,新增了一个createProduct2方法

package com.zwx.design.pattern.factory.simple;

public class SimpleFactory {
     
    public IProduct createProduct(String productType){
     
        if("apple".equals(productType)){
     
            return new Apple();
        }else if("orange".equals(productType)){
     
            return new Orange();
        }
        return null;
    }

    public IProduct createProduct2(Class<? extends IProduct> clazz) throws Exception {
     
        if (null == clazz){
     
            throw new Exception("无法识别的产品");
        }
        return clazz.newInstance();
    }
}

测试类:

package com.zwx.design.pattern.factory.simple;

public class TestSimpleFactory {
     
    public static void main(String[] args) throws Exception {
     
        SimpleFactory factory = new SimpleFactory();
        IProduct apple = factory.createProduct2(Apple.class);
        apple.grow();//输出:种植苹果

        IProduct orange = factory.createProduct2(Orange.class);
        orange.grow();//输出:种植桔子
    }
}

可以看到,这种写法解决了可能存在的if分支过多造成工厂类臃肿的问题,但是这种方法真的完美吗?请继续往下看。。。

简单工厂模式适用场景

简单工厂适用于工厂类负责创建的对象较少的场景,且客户端只需要传入工厂类的参数,对于如何创建对象的逻辑不需要关心

简单工厂模式缺点

假如每种产品创建不仅仅只是实例化一个对象,还有其他逻辑需要处理,那么我们无法直接使用一句反射,避免不了写很多if(亦或者用switch循环),这样的话每新增一个产品我们都需要修改工厂实现类,随着产品链越来越丰富,工厂的职责会变得越来越多,久而久之会越来越难以维护。

工厂方法模式(Fatory Method Pattern)

工厂方法模式是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个对象,工厂方法让类的实例化推迟到子类中进行,在工厂方法模式中用户只需要关心所需产品对应的工厂,无须关心创建细节,而且加入新的产品符合开闭原则。

新建一个产品接口

package com.zwx.design.pattern.factory.method;

public interface IProduct {
     
    void grow();
}

新建一个具体产品苹果类

package com.zwx.design.pattern.factory.method;

public class Apple implements IProduct {
     
    @Override
    public void grow() {
     
        System.out.println("种植苹果");
    }
}

新建一个具体产品桔子类

package com.zwx.design.pattern.factory.method;

public class Orange implements IProduct {
     
    @Override
    public void grow() {
     
        System.out.println("种植桔子");
    }
}

现在我们需要将工厂也抽象化:
新建一个工厂接口,定义一个create方法,这个方法的返回值就是产品

package com.zwx.design.pattern.factory.method;

public interface IFarmFactory {
     
    IProduct create();
}

新建一个生产苹果的具体工厂类,并实现工厂接口IFarmFactory

package com.zwx.design.pattern.factory.method;

public class AppleFactory implements IFarmFactory {
     
    @Override
    public IProduct create() {
     
        return new Apple();
    }
}

新建一个生产桔子的具体工厂类,并实现工厂接口IFarmFactory

package com.zwx.design.pattern.factory.method;

public class OrangeFactory implements IFarmFactory {
     
    @Override
    public IProduct create() {
     
        return new Orange();
    }
}

最后,添加测试类

package com.zwx.design.pattern.factory.method;

public class TestFactoryMethod {
     
    public static void main(String[] args) {
     
        IFarmFactory appleFactory = new AppleFactory();
        IProduct apple = appleFactory.create();
        apple.grow();//输出:种植苹果

        IFarmFactory orangeFactory = new OrangeFactory();
        IProduct orange = orangeFactory.create();
        orange.grow();//输出:种植桔子
    }
}

这时候如果需要新增其他商品,需要创建两个类:一个具体产品类,一个具体工厂类。

看完这个例子家应该很明白工厂方法和简单工厂的区别了,简单工厂就是所有产品都由一个工厂类一个方法来创建,而工厂方法将工厂的职责也进行细化了,每种产品都由自己特定的工厂来生产,这也是单一职责原则的体现。

工厂方法模式适用场景

1、创建对象需要大量重复的代码。
2、客户端(应用层)不依赖于产品类实例如何被创建、实现等细节。
3、一个类通过其子类来指定创建哪个对象。

工厂方法模式缺点

1、类的个数容易过多,增加复杂度。
2、增加了系统的抽象性和理解难度

抽象工厂模式(Abstract Factory Pattern)

抽象工厂模式是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。客户端(应用层)不依赖于产品类实例如何被创建、实现等细节,强调的是一系列相关的产品对象(属于同一产品族)一起使用创建对象需要大量重复的代码。需要提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。

抽象工厂示例

新建一个苹果的接口,定义一个种植苹果的方法

package com.zwx.design.pattern.factory.abstractMethod;

public interface IApple {
     
   void growApple();
}

新建一个具体产品南方苹果类来实现IApple接口

package com.zwx.design.pattern.factory.abstractMethod;

public class SouthApple implements IApple {
     
    @Override
    public void growApple() {
     
        System.out.println("种植南方苹果");
    }
}

新建一个桔子的接口,定义一个种植桔子的方法

package com.zwx.design.pattern.factory.abstractMethod;

public interface IOrange {
     
    void growOrange();
}

新建一个具体产品南方桔子类来实现IOrange接口

package com.zwx.design.pattern.factory.abstractMethod;

public class SouthOrange implements IOrange {
     
    @Override
    public void growOrange() {
     
        System.out.println("种植南方桔子");
    }
}

以上就是一个将产品抽象化的过程,接下来我们就需要将产品交给工厂进行创建。

新建一个抽象工厂接口,定义两个方法:一个用来创建苹果对象,一个用来创建桔子对象

package com.zwx.design.pattern.factory.abstractMethod;

public interface IFactory {
     
    IApple createApple();
    IOrange createOrange();
}

新建一个具体工厂南方工厂类来实现IFactory接口,并实现其中的两个抽象方法

package com.zwx.design.pattern.factory.abstractMethod;

import com.zwx.design.pattern.factory.method.IProduct;

public class SouthFarmFactory implements IFactory {
     
    @Override
    public IApple createApple() {
     
        return new SouthApple();
    }

    @Override
    public IOrange createOrange() {
     
        return new SouthOrange();
    }
}

最后我们来测试一下

package com.zwx.design.pattern.factory.abstractMethod;

public class TestAbstractFactory {
     
    public static void main(String[] args) {
     
        IFactory southFarmFactory = new SouthFarmFactory();
        IApple apple = southFarmFactory.createApple();
        apple.growApple();//输出:种植南方苹果

        IOrange orange = southFarmFactory.createOrange();
        orange.growOrange();//输出:种植南方桔子
    }
}

假如说这时候又有一个新的农场要建立生产一样的产品,那么就可以再新建一个对应的产品类和对应的工厂类就可以实现了。

抽象工厂使用场景

当我们有一系列产品(如上面的Apple,Orange)。而这一系列产品每种产品又需要具有不同的创建方法(如上种植Apple和种植Orange方法肯定是不同的需要不同的方法实现)。

抽象工厂缺点

1、规定了所有可能被创建的产品集合,产品族中扩展新的产品困难,需要修改抽象工厂
的接口。
2、增加了系统的抽象性和理解难度。

总结

本文主要介绍了三种工厂模式的实现,其中简单工厂模式并不属于GoF23中设计模式之一。并且针对每种工厂模式给出了对比和代码示例帮助理解,每种工厂模式都适用于不同的业务场景,实际开发过程中可以根据需要进行选择。

你可能感兴趣的:(设计模式,设计模式,简单工厂,工厂方法,抽象工厂,工厂模式)