【设计模式】简单工厂,工厂方法,抽象工厂的区别

内容纲要

概念

简单工厂、抽象工厂和工厂方法都是创建型设计模式,它们都与对象创建相关,但它们之间存在一些区别:

  • 简单工厂模式(Simple Factory Pattern):简单工厂模式又称为静态工厂方法模式,是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式实现简单,但是如果要添加新的产品,就需要修改工厂类的代码,违反了“开闭原则”。

  • 工厂方法模式(Factory Method Pattern):工厂方法模式定义了一个抽象的工厂类,具体的工厂类负责创建具体的产品对象,每个工厂类只负责创建单一的产品。这样每次添加新的产品,只需要添加一个新的具体工厂类即可。工厂方法模式符合“开闭原则”。

  • 抽象工厂模式(Abstract Factory Pattern):抽象工厂模式定义了一个抽象工厂接口,用于创建一组相关或者相互依赖的对象。抽象工厂模式可以同时创建多个对象,与工厂方法模式的区别是,工厂方法模式只能创建一个对象,而抽象工厂模式可以创建多个对象。

总之,三种工厂模式都是为了解决对象创建问题而提出的。简单工厂模式实现简单,但是不符合开闭原则,违反了“对扩展开放,对修改关闭”的设计原则;工厂方法模式可以避免修改原有代码,但是需要为每个产品定义一个工厂类,增加了类的数量;抽象工厂模式适用于创建一组相关的产品对象。

例子

简单工厂模式

假设有两个形状类:Circle(圆形)和 Square(正方形),它们都实现了一个形状接口 Shape。我们现在需要一个形状工厂,根据不同的参数来创建不同的形状对象。
首先,定义 Shape 接口:

public interface Shape {
    void draw();
}

然后,定义两个形状类:

public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Circle.draw()");
    }
}

public class Square implements Shape {
    @Override
    public void draw() {
        System.out.println("Square.draw()");
    }
}

最后,定义一个形状工厂类 ShapeFactory,根据传入的参数来创建不同的形状对象:

public class ShapeFactory {
    public static final String CIRCLE = "circle";
    public static final String SQUARE = "square";

    public static Shape getShape(String shapeType) {
        if (shapeType == null) {
            return null;
        }
        if (shapeType.equalsIgnoreCase(CIRCLE)) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase(SQUARE)) {
            return new Square();
        }
        return null;
    }
}

现在,我们可以通过调用 ShapeFactory.getShape() 方法来获取不同的形状对象:

Shape circle = ShapeFactory.getShape("circle");
circle.draw(); // 输出 "Circle.draw()"

Shape square = ShapeFactory.getShape("square");
square.draw(); // 输出 "Square.draw()"

以上就是一个简单工厂模式的 Java 实现。注意,这个简单工厂模式的实现只适用于创建形状对象,如果需要创建其他类型的对象,就需要创建新的工厂类。

工厂方法模式

工厂方法模式是一种常见的创建型设计模式,其定义了一个用于创建对象的接口,但是由子类决定要实例化的类是哪一个,也就是说,工厂方法模式将实例化的任务委托给了子类。

下面是一个工厂方法模式的例子:假设我们有一个披萨店,有不同口味的披萨,例如芝士披萨、蛤蜊披萨、意大利香肠披萨等等,我们需要根据不同的口味创建不同的披萨。

首先,定义一个披萨接口:

public interface Pizza {
    void prepare();
    void bake();
    void cut();
    void box();
}

然后,定义具体的披萨类:

public class CheesePizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备芝士披萨");
    }

    @Override
    public void bake() {
        System.out.println("烘焙芝士披萨");
    }

    @Override
    public void cut() {
        System.out.println("切芝士披萨");
    }

    @Override
    public void box() {
        System.out.println("装箱芝士披萨");
    }
}

public class ClamPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备蛤蜊披萨");
    }

    @Override
    public void bake() {
        System.out.println("烘焙蛤蜊披萨");
    }

    @Override
    public void cut() {
        System.out.println("切蛤蜊披萨");
    }

    @Override
    public void box() {
        System.out.println("装箱蛤蜊披萨");
    }
}

public class PepperoniPizza implements Pizza {
    @Override
    public void prepare() {
        System.out.println("准备意大利香肠披萨");
    }

    @Override
    public void bake() {
        System.out.println("烘焙意大利香肠披萨");
    }

    @Override
    public void cut() {
        System.out.println("切意大利香肠披萨");
    }

    @Override
    public void box() {
        System.out.println("装箱意大利香肠披萨");
    }
}

接下来,定义披萨工厂接口:

public interface PizzaFactory {
    Pizza createPizza();
}

然后,定义不同口味的披萨工厂的具体实现类:

public class CheesePizzaFactory implements PizzaFactory {
    @Override
    public Pizza createPizza() {
        return new CheesePizza();
    }
}

public class ClamPizzaFactory implements PizzaFactory {
    @Override
    public Pizza createPizza() {
        return new ClamPizza();
    }
}

public class PepperoniPizzaFactory implements PizzaFactory {
    @Override
    public Pizza createPizza() {
        return new PepperoniPizza();
    }
}
问题

上述的工厂类只是new了一个实例,那我直接new这个对象不行吗?

PizzaFactory factory= new PepperoniPizzaFactory();
Pizza pizza = factory.createPizza();
pizza.doSomething()

为什么不修改成,这样明明更简单啊,还少了很多的类

Pizza pizza = new PepperoniPizza();
pizza.doSomething()

原因一:工厂方法的createPizza方法可能没有这个实例这么简单,它可能包含更复杂的逻辑,比如使用缓存来减少真正创建的实例
https://refactoringguru.cn/design-patterns/factory-method
file

抽象工厂模式 例1

下面是一个 Java 实现抽象工厂模式的例子:

假设我们需要开发一个游戏,游戏中有两个角色:魔法师(Magician)和战士(Warrior),每个角色都可以穿不同的装备:铠甲(Armor)和魔法棒(Wand)。

首先,定义两个角色接口 Magician 和 Warrior:

public interface Magician {
    void cast();
}

public interface Warrior {
    void attack();
}

然后,定义两个装备接口 Armor 和 Wand:

public interface Armor {
    void defend();
}

public interface Wand {
    void wave();
}

接下来,定义两个角色的具体实现类 MagicianImpl 和 WarriorImpl:

public class MagicianImpl implements Magician {
    @Override
    public void cast() {
        System.out.println("Magician casts a spell");
    }
}

public class WarriorImpl implements Warrior {
    @Override
    public void attack() {
        System.out.println("Warrior swings a sword");
    }
}

再定义两个装备的具体实现类 ArmorImpl 和 WandImpl:

public class ArmorImpl implements Armor {
    @Override
    public void defend() {
        System.out.println("Armor defends the character");
    }
}

public class WandImpl implements Wand {
    @Override
    public void wave() {
        System.out.println("Wand waves and casts magic");
    }
}

最后,定义一个抽象工厂接口 GameFactory,该接口有两个方法,分别用于创建 Magician 和 Warrior 以及对应的装备:

public interface GameFactory {
    Magician createMagician();
    Warrior createWarrior();
    Armor createArmor();
    Wand createWand();
}

现在,我们可以定义具体的工厂类来实现 GameFactory 接口,例如,定义一个魔幻游戏工厂 MagicGameFactory,该工厂可以创建魔法师和战士以及对应的装备:

public class MagicGameFactory implements GameFactory {
    @Override
    public Magician createMagician() {
        return new MagicianImpl();
    }

    @Override
    public Warrior createWarrior() {
        return new WarriorImpl();
    }

    @Override
    public Armor createArmor() {
        return new ArmorImpl();
    }

    @Override
    public Wand createWand() {
        return new WandImpl();
    }
}

现在,我们可以使用 MagicGameFactory 来创建角色和装备,并使用它们来玩游戏:

GameFactory factory = new MagicGameFactory();
Magician magician = factory.createMagician();
Warrior warrior = factory.createWarrior();
Armor armor = factory.createArmor();
Wand wand = factory.createWand();

magician.cast(); // 输出 "Magician casts a spell"
warrior.attack(); // 输出 "Warrior swings a sword"
armor.defend(); // 输出 "Armor defends the character"
wand.wave(); // 输出 "Wand waves and casts magic"

以上就是一个抽象工厂模式的 Java 实现。注意,如果需要创建新的角色或装备,可以创建新的具体工厂类来实现 GameFactory 接口。

抽象工厂模式 例2

假设我们需要创建一个电脑工厂,可以生产联想电脑和戴尔电脑,联想电脑包括联想台式机和联想笔记本电脑,戴尔电脑包括戴尔台式机和戴尔笔记本电脑。

首先,定义电脑接口:

public interface Computer {
    void printInfo();
}

然后,定义联想电脑和戴尔电脑的具体实现类:

public class LenovoDesktop implements Computer {
    @Override
    public void printInfo() {
        System.out.println("生产联想台式机");
    }
}

public class LenovoLaptop implements Computer {
    @Override
    public void printInfo() {
        System.out.println("生产联想笔记本电脑");
    }
}

public class DellDesktop implements Computer {
    @Override
    public void printInfo() {
        System.out.println("生产戴尔台式机");
    }
}

public class DellLaptop implements Computer {
    @Override
    public void printInfo() {
        System.out.println("生产戴尔笔记本电脑");
    }
}

接下来,定义抽象工厂接口:

public interface ComputerFactory {
    Computer createDesktopComputer();
    Computer createLaptopComputer();
}

然后,定义联想电脑工厂和戴尔电脑工厂的具体实现类:

public class LenovoComputerFactory implements ComputerFactory {
    @Override
    public Computer createDesktopComputer() {
        return new LenovoDesktop();
    }

    @Override
    public Computer createLaptopComputer() {
        return new LenovoLaptop();
    }
}

public class DellComputerFactory implements ComputerFactory {
    @Override
    public Computer createDesktopComputer() {
        return new DellDesktop();
    }

    @Override
    public Computer createLaptopComputer() {
        return new DellLaptop();
    }
}

现在,我们可以通过调用不同的电脑工厂的方法来生产不同品牌的电脑:

ComputerFactory lenovoFactory = new LenovoComputerFactory();
Computer desktop = lenovoFactory.createDesktopComputer();
Computer laptop = lenovoFactory.createLaptopComputer();
desktop.printInfo(); // 输出 "生产联想台式机"
laptop.printInfo(); // 输出 "生产联想笔记本电脑"

ComputerFactory dellFactory = new DellComputerFactory();
desktop = dellFactory.createDesktopComputer();
laptop = dellFactory.createLaptopComputer();
desktop.printInfo(); // 输出 "生产戴尔台式机"
laptop.printInfo(); // 输出 "生产戴尔笔记本电脑"

以上就是一个抽象工厂模式的 Java 实现。注意,抽象工厂模式适用于创建一组相关的对象,如果需要创建其他类型的对象,就需要创建新的工厂接口和实现类。

【设计模式】简单工厂,工厂方法,抽象工厂的区别

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注

滚动到顶部