工厂方法模式

Posted wanghan5950

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了工厂方法模式相关的知识,希望对你有一定的参考价值。

工厂方法模式的应用非常广泛,结构也比较简单。在我们需要创建复杂对象,或创建实现某个接口的对象时,为了隐藏创建对象的过程,就可以用工厂方法来代替直接的new一个对象。从而达到对复杂对象的创建进行统一管理,或接口与实现相分离的目的。

工厂方法模式可以按照工厂的多少分为三类:

1.简单工厂模式或静态工厂模式

例如现在要生产复杂的SimpleProduct对象,因为只有一种要生产的对象,无需对其进行抽象,所以直接可以创建如下的工厂:

public class SimpleFactory {
    
    public static SimpleProduct createSimpleProduct() {
        //创建SimpleProduct对象
        return new SimpleProduct();
    }
}

简单工厂适用于确定只有单一的复杂对象需要生产的场景。

2.多工厂的工厂方法模式

如果要生产的复杂对象是同一类别的不同实现类,如ProductA和ProductB,此时需要不同的工厂来对应生产这两种对象。我们首先建立产品的抽象类或接口,具体的产品来实现:

public abstract class Product {

    /**
     * 定义抽象产品方法,具体产品实现
     */
    public abstract void work();
}
public class ProductA extends Product {

    @Override
    public void work() {
        System.out.println("this is product A");
    }
}
public class ProductB extends Product {

    @Override
    public void work() {
        System.out.println("this is product B");
    }
}

有了产品的抽象,我们再创建工厂的抽象,并在生产产品对象的方法中返回产品的抽象,在工厂实现中创建不同的产品:

public abstract class ProductFactory {

    /**
     * 定义抽象工厂方法,具体工厂实现
     * @return 产品的抽象
     */
    public abstract Product createProduct();
}
public class ProductFactoryA extends ProductFactory {

    @Override
    public Product createProduct() {
        return new ProductA();
    }
}
public class ProductFactoryB extends ProductFactory {

    @Override
    public Product createProduct() {
        return new ProductB();
    }
}

当需要产品对象时,直接通过对应的工厂来创建,我们不关心不同产品的创建过程。因为客户类依赖的是产品的抽象,如果需要更换产品,只需要修改工厂方法中创建产品的实现,或增加新产品的实现和对应的工厂实现。这样,将接口与实现相分离,提高了代码的可维护性和可扩展性。

3.抽象工厂模式

普通的工厂方法模式中,只有Product基类这一种产品,当需要生产多种类别的产品时,就需要升级到抽象工厂模式了。

举例,PC厂商会生产鼠标键盘等产品,如果只生产一种,比如鼠标,就直接按照上面普通工厂模式的写法,如果既要生产鼠标又要生产键盘就要使用抽象工厂了。

现在建立PC厂商抽象工厂和鼠标,键盘两种产品的抽象:

public abstract class PCFactory {

    public abstract Mouse createMouse();
    
    public abstract Keyboard createKeyboard();
}
public abstract class Mouse {

    public abstract void method();
}
public abstract class Keyboard {

    public abstract void method();
}

现在有戴尔,惠普两个厂商,都会生产自家品牌的这两种产品。因此要实现两个厂商的产品类和厂商工厂类,并在各自的工厂方法中返回自家的产品对象:

惠普的产品

public class HPMouse extends Mouse {

    @Override
    public void method() {
        System.out.println("this is HP Mouse");
    }
}
public class HPKeyboard extends Keyboard {

    @Override
    public void method() {
        System.out.println("this is HP Keyboard");
    }
}

戴尔的产品

public class DELLMouse extends Mouse {

    @Override
    public void method() {
        System.out.println("this is DELL Mouse");
    }
}
public class DELLKeyboard extends Keyboard {

    @Override
    public void method() {
        System.out.println("this is DELL Keyboard");
    }
}

两个厂商的工厂类,并在工厂方法中返回自家的产品对象:

public class HPPCFactory extends PCFactory {

    @Override
    public Mouse createMouse() {
        return new HPMouse();
    }

    @Override
    public Keyboard createKeyboard() {
        return new HPKeyboard();
    }
}
public class DELLPCFactory extends PCFactory {

    @Override
    public Mouse createMouse() {
        return new DELLMouse();
    }

    @Override
    public Keyboard createKeyboard() {
        return new DELLKeyboard();
    }
}

客户端调用,要生产戴尔的产品:

public class Client {

    public static void main(String[] args) {
        PCFactory factory = new DELLPCFactory();
        Mouse mouse = factory.createMouse();
        Keyboard keyboard = factory.createKeyboard();
        mouse.method();
        keyboard.method();
    }
}

如果需要换成其它厂商的产品,我们只需要将new DELLPCFactory()更换为另一个工厂,生产出的产品即为该厂商的产品。新增厂商需要再实现对应的工厂和产品类。

为了继续隐藏创建工厂时new一个具体工厂的操作,让客户端不依赖具体工厂,还可增加一个工厂的工厂类:

public class PCFactoryProvider {

    public static PCFactory getPCFactory(String type) {
        if (type.equals("DELL")) {
            return new DELLPCFactory();
        } else if (type.equals("HP")) {
            return new HPPCFactory();
        }
        return null;
    }
}

客户端调用:

public class Client {

    public static void main(String[] args) {
        PCFactory factory = PCFactoryProvider.getPCFactory("DELL");
        if (factory != null) {
            Mouse dellMouse = factory.createMouse();
            Keyboard dellKeyboard = factory.createKeyboard();
            dellMouse.method();
            dellKeyboard.method();
        }
    }
}

这样,客户端只是面向接口编程而已,不需要依赖具体的工厂和产品实现,在切换产品时会更加灵活。当然,抽象工厂的缺点也很明显,不仅类的数量众多,而且当需要新增产品类别时,由于修改了工厂抽象方法,导致所有的工厂实现和都需要改动。

以上是关于工厂方法模式的主要内容,如果未能解决你的问题,请参考以下文章

设计模式-简单工厂工厂方法模式抽象工厂模式详解

工厂方法模式

设计模式-工厂方法模式(Go实现)

C++工厂模式(简单工厂工厂方法抽象工厂)

C++工厂模式(简单工厂工厂方法抽象工厂)

设计模式---工厂模式