设计模式之工厂模式

介绍:

工厂模式专门负责及那个大量有共同接口的类实例化,工厂模式可以动态决定奖哪一个类实例化,不必事先知道每次要实例化哪一个类。工厂模式有一下几种形态:

  • 简单工厂模式:又称静态工厂方法模式,是不同的工厂方法模式的一个特殊实现。
  • 工厂方法模式:又称多态性工厂模式
  • 抽象工厂模式:又称工具箱模式

简单工厂模式:

比如说有一个农场公司,专门向市场销售以下水果:葡萄(Grape)、草莓(Strawberry)、苹果(Apple)。

水果接口规定出所有的水果必须实现的接口:种植plant()、生长grow()、收获harvest().

其UML类图如下:

那么水果接口的代码如下:

package com.charon.factory.simpleFactory;

/**
 * @className: Fruit
 * @description: 水果接口
 * @author: charon
 * @create: 2022-03-06 20:30
 */
public interface Fruit {

    /**
     * 种植
     */
    void plant();

    /**
     * 生长
     */
    void grow();

    /**
     * 收获
     */
    void harvest();
}

草莓类是水果类的一种,因此他实现了水果接口中所有声明的方法。

package com.charon.factory.simpleFactory;

/**
 * @className: Strawberry
 * @description:
 * @author: charon
 * @create: 2022-03-06 20:43
 */
public class Strawberry implements Fruit{

    @Override
    public void plant() {
        System.out.println("草莓种植了。。。。");
    }

    @Override
    public void grow() {
        System.out.println("草莓生长中。。。。");
    }

    @Override
    public void harvest() {
        System.out.println("草莓收获了。。。。");
    }
}

苹果类也是水果类的一种,因此他实现了水果接口中所有声明的方法:

package com.charon.factory.simpleFactory;

/**
 * @className: Apple
 * @description:
 * @author: charon
 * @create: 2022-03-06 20:36
 */
public class Apple implements Fruit{

    @Override
    public void plant() {
        System.out.println("苹果树种植了。。。。");
    }

    @Override
    public void grow() {
        System.out.println("苹果树生长中。。。。");
    }

    @Override
    public void harvest() {
        System.out.println("苹果树收获了。。。。");
    }
}

葡萄类也是水果类的一种,因此他实现了水果接口中所有声明的方法:

package com.charon.factory.simpleFactory;

/**
 * @className: Grape
 * @description:
 * @author: charon
 * @create: 2022-03-06 20:41
 */
public class Grape implements Fruit{

    @Override
    public void plant() {
        System.out.println("葡萄种植了。。。。");
    }

    @Override
    public void grow() {
        System.out.println("葡萄生长中。。。。");
    }

    @Override
    public void harvest() {
        System.out.println("葡萄收获了。。。。");
    }
}

FruitGardener类是园丁类,会根据客户端的要求,创建出不同的水果对象,所有的创建对象的任务都由这个类完成。

package com.charon.factory.simpleFactory;

/**
 * @className: FruitGardener
 * @description: 园丁类
 * @author: charon
 * @create: 2022-03-06 20:46
 */
public class FruitGardener {

    /**
     * 静态工厂方法
     *
     * @param fruitType 水果类型
     * @return
     */
    public static Fruit factory(String fruitType) {
        if ("apple".equalsIgnoreCase(fruitType)) {
            return new Apple();
        } else if ("Grape".equalsIgnoreCase(fruitType)) {
            return new Grape();
        } else if ("Strawberry".equalsIgnoreCase(fruitType)) {
            return new Strawberry();
        } 
        return null;
    }
}

测试:

package com.charon.factory.simpleFactory;

/**
 * @className: Test
 * @description:
 * @author: charon
 * @create: 2022-03-06 20:50
 */
public class Test {
    public static void main(String[] args) {
        Fruit apple = FruitGardener.factory("apple");
        apple.plant();
        apple.grow();
        apple.harvest();
        Fruit grape = FruitGardener.factory("grape");
        grape.plant();
        grape.grow();
        grape.harvest();
        Fruit strawberry = FruitGardener.factory("strawberry");
        strawberry.plant();
        strawberry.grow();
        strawberry.harvest();
    }
}
打印结果:
    苹果树种植了。。。。
    苹果树生长中。。。。
    苹果树收获了。。。。
    
    葡萄种植了。。。。
    葡萄生长中。。。。
    葡萄收获了。。。。
    
    草莓种植了。。。。
    草莓生长中。。。。
    草莓收获了。。。。

简单工厂模式就是由一个工厂类根据传入的参数决定创建出哪一种产品的类的实例。

这种模式的优点:好理解,简单易操作。

这种模式的缺点:违反了设计模式的ocp原则,即对扩展开放,对修改关闭。

如果我们需要新添加一种水果,那么需要新添加一个水果类,还需要在FruitGardener中添加这种水果的实例化。同时,由于使用的静态方法作为的工厂方法,而静态方法无法由子类继承,因此,工厂角色无法形成基于继承的等级结构。

从上面可以知道,简单工厂模式涉及到工厂角色、抽象产品角色以及具体产品角色:

  • 工厂角色:担任这个角色的是工厂方法模式的核心,含有与应用紧密相关的商业逻辑,工厂类在客户端的直接调用下创建产品对象,往往由一个具体的java类实现
  • 抽象产品角色:担任这个角色的类是由工厂方法模式所创建的对象的父类,或他们共同拥有的接口,抽象产品角色可以用一个java接口或者java抽象类实现
  • 具体产品角色:工厂方法模式所创建的任何对象都是这个角色的实例,具体产品角色由一个个具体的java类实现

工厂方法模式:

工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了多态性,工厂方法模式保持了简单工厂模式的优点,也克服了他的缺点。在工厂方法模式中,核心的工厂类不再负责所有的产品的创建,而是将具体创建的工作交给子类去做,这个核心类则成为了一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不是接触哪一个产品类应当被实例化这种细节。

还是上面的例子。由于农场规模扩大,一个园丁已经处理不过来了,所以现在每一种水果都需要专门的园丁来管理了。那么上面的FruitGardener这个全能角色就成了抽象的园丁角色,这个角色规定出具体园丁角色需要实现的具体职能,而真正负责水果管理的则是具体的园丁角色。

本系统的UML类图如下:

FruitGardener接口类:

package com.charon.factory.factoryMethod;

import com.charon.factory.simpleFactory.Fruit;

/**
 * @className: FruitGardener
 * @description: 园丁类
 * @author: charon
 * @create: 2022-03-06 20:46
 */
public interface FruitGardener {

    /**
     * 静态工厂方法
     *
     * @param fruitType 水果类型
     * @return
     */
    Fruit factory();

}

AppleGardener类是具体工厂类,它实现了FruitGardener 接口,提供了工厂方法的实现:

package com.charon.factory.factoryMethod;

import com.charon.factory.simpleFactory.Apple;
import com.charon.factory.simpleFactory.Fruit;

/**
 * @className: AppleGardener
 * @description:
 * @author: charon
 * @create: 2022-03-06 23:04
 */
public class AppleGardener implements FruitGardener{
    @Override
    public Fruit factory() {
        return new Apple();
    }
}

GrapeGardener类是具体工厂类,它实现了FruitGardener 接口,提供了工厂方法的实现:

package com.charon.factory.factoryMethod;

import com.charon.factory.simpleFactory.Fruit;
import com.charon.factory.simpleFactory.Grape;

/**
 * @className: GrapeGardener
 * @description:
 * @author: charon
 * @create: 2022-03-06 23:04
 */
public class GrapeGardener implements FruitGardener{
    @Override
    public Fruit factory() {
        return new Grape();
    }
}

StrawberryGardener类是具体工厂类,它实现了FruitGardener 接口,提供了工厂方法的实现:

package com.charon.factory.factoryMethod;

import com.charon.factory.simpleFactory.Fruit;
import com.charon.factory.simpleFactory.Strawberry;

/**
 * @className: StrawberryGardener
 * @description:
 * @author: charon
 * @create: 2022-03-06 23:04
 */
public class StrawberryGardener implements FruitGardener{
    @Override
    public Fruit factory() {
        return new Strawberry();
    }
}

Test类:

package com.charon.factory.factoryMethod;

import com.charon.factory.simpleFactory.Fruit;

/**
 * @className: Test
 * @description:
 * @author: charon
 * @create: 2022-03-06 23:11
 */
public class Test {

    public static void main(String[] args) {
        FruitGardener appleGardener = new AppleGardener();
        Fruit apple = appleGardener.factory();
        apple.plant();
        apple.plant();
        apple.harvest();

        FruitGardener grapeGardener = new GrapeGardener();
        Fruit grape = grapeGardener.factory();
        grape.plant();
        grape.plant();
        grape.harvest();

        FruitGardener strawberryGardener = new StrawberryGardener();
        Fruit strawberry = strawberryGardener.factory();
        strawberry.plant();
        strawberry.plant();
        strawberry.harvest();
    }
}
打印结果:
    苹果树种植了。。。。
    苹果树生长中。。。。
    苹果树收获了。。。。
    
    葡萄种植了。。。。
    葡萄生长中。。。。
    葡萄收获了。。。。
    
    草莓种植了。。。。
    草莓生长中。。。。
    草莓收获了。。。。

从上面可以知道,工厂方法模式涉及到抽象工厂角色、具体工厂角色、抽象产品角色以及具体产品角色:

  • 抽象工厂角色:担任这个角色的是工厂方法模式的核心,它是与应用程序无关的。任何在模式中创建对象的工厂类必须实现这个接口。这个角色也常常使用抽象Java类实现。
  • 具体工厂角色:担任这个角色的是实现了抽象工厂接口的具体Java类。具体工厂角色含有与应用密切相关的逻辑,并且受到应用程序的调用以创建产品对象。
  • 抽象产品角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。这个角色也常常使用抽象Java类实现。
  • 具体产品角色:这个角色实现了抽象产品角色所声明的接口。工厂方法模式所创建的每一个对象都是某个具体产品角色的实例。

抽象工厂模式:

抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。这就是抽象工厂模式的用意。

为了方便引进抽象工厂模式,特地引进了一个新的概念:产品族,是指与不同产品等级结构中功能相关联的产品组成的家族。

还是上面的例子。随着市场的扩大,农场公司再次面临新的发展,引入了蔬菜大棚技术,在大棚内种植热带和亚热带的水果和蔬菜。

因此在这个系统里,产品分成两个等级结构:水果(热带水果,亚热带水果)和蔬菜(热带蔬菜,亚热带蔬菜)。园丁呢,也分成两类:管理热带水果蔬菜的园丁(tropicGardener)和管理亚热带水果蔬菜的园丁(subtropicalGardener)。

本系统的UML类图如下:

Fruit 水果接口类:

package com.charon.factory.absFactory;

/**
 * @className: Fruit
 * @description: 水果类
 * @author: charon
 * @create: 2022-03-08 22:12
 */
public interface Fruit {
}

TropicFruit 热带水果实现类:

package com.charon.factory.absFactory;

/**
 * @className: TropicFruit
 * @description: 热带水果
 * @author: charon
 * @create: 2022-03-08 22:13
 */
public class TropicFruit implements Fruit{

    private String name;

    public TropicFruit(String name) {
        this.name = name;
        System.out.println("热带水果: "+ name);
    }
}

SubtropicFruit 亚热带水果实现类:

package com.charon.factory.absFactory;

/**
 * @className: TropicFruit
 * @description: 亚热带水果
 * @author: charon
 * @create: 2022-03-08 22:13
 */
public class SubtropicFruit implements Fruit{

    private String name;

    public SubtropicFruit(String name) {
        this.name = name;
        System.out.println("亚热带水果: "+ name);
    }
}

Veggie 蔬菜类接口:

package com.charon.factory.absFactory;

/**
 * @className: Veggie
 * @description: 蔬菜类
 * @author: charon
 * @create: 2022-03-08 22:12
 */
public interface Veggie {
}

TropicVeggie 热带蔬菜:

package com.charon.factory.absFactory;

/**
 * @className: TropicVeggie
 * @description: 热带蔬菜
 * @author: charon
 * @create: 2022-03-08 22:13
 */
public class TropicVeggie implements Veggie{

    private String name;

    public TropicVeggie(String name) {
        this.name = name;
        System.out.println("热带蔬菜: "+ name);
    }
}

SubtropicVeggie 亚热带蔬菜:

package com.charon.factory.absFactory;

/**
 * @className: TropicVeggie
 * @description: 热带蔬菜
 * @author: charon
 * @create: 2022-03-08 22:13
 */
public class SubtropicVeggie implements Veggie{

    private String name;

    public SubtropicVeggie(String name) {
        this.name = name;
        System.out.println("亚热带蔬菜: "+ name);
    }
}

Gardener 园丁接口类:

package com.charon.factory.absFactory;

/**
 * @className: Gardener
 * @description: 园丁的顶级接口
 * @author: charon
 * @create: 2022-03-08 22:09
 */
public interface Gardener {

    /**
     * 创建亚热带水果
     * @return
     */
    Fruit createFruit();

    /**
     * 创建亚热带蔬菜
     * @return
     */
    Veggie createVeggie();
}

TropicGardener 热带园丁类:

package com.charon.factory.absFactory;

/**
 * @className: TropicGardener
 * @description: 管理热带水果蔬菜的园丁类
 * @author: charon
 * @create: 2022-03-08 22:10
 */
public class TropicGardener implements Gardener{

    /**
     * 创建热带水果
     * @return
     */
    @Override
    public Fruit createFruit(){
        return new TropicFruit("苹果");
    }

    /**
     * 创建热带蔬菜
     * @return
     */
    @Override
    public Veggie createVeggie(){
        return new TropicVeggie("白菜");
    }
}

SubtropicGardener 亚热带园丁类:

package com.charon.factory.absFactory;

import java.util.concurrent.Future;

/**
 * @className: SubtropicGardener
 * @description: 管理亚热带水果蔬菜的园丁类
 * @author: charon
 * @create: 2022-03-08 22:11
 */
public class SubtropicGardener implements Gardener{

    /**
     * 创建亚热带水果
     * @return
     */
    @Override
    public Fruit createFruit(){
       return new SubtropicFruit("苹果");
    }

    /**
     * 创建亚热带蔬菜
     * @return
     */
    @Override
    public Veggie createVeggie(){
        return new SubtropicVeggie("白菜");
    }
}

test 测试类:

package com.charon.factory.absFactory;


/**
 * @className: Test
 * @description:
 * @author: charon
 * @create: 2022-03-08 22:23
 */
public class Test {

    public static void main(String[] args) {
        Gardener tropicGardener = new TropicGardener();
        tropicGardener.createFruit();
        tropicGardener.createVeggie();

        Gardener subtropicGardener = new SubtropicGardener();
        subtropicGardener.createFruit();
        subtropicGardener.createVeggie();
    }
}

抽象工厂模式涉及到一下的角色:

  • 抽象工厂角色:担任这个角色的是工厂方法模式的核心,它是与应用系统的商业逻辑无关的。通常是使用java接口或者抽象java类实现,而所有的具体工厂类必须实现这个java接口或继承这个抽象java类
  • 具体工厂类角色:这个角色直接在客户端的调用下创建产品的实例,这个角色含有选择的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。通常使用具体java类实现的这个角色
  • 抽象产品角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或他们共同拥有的接口,通常使用java接口或者抽象java类实现这一角色
  • 具体产品角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例,这事客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑,通常使用具体的java类实现这个角色
posted @ 2022-03-10 21:07  pluto_charon  阅读(184)  评论(0编辑  收藏  举报