设计模式之工厂模式


工厂模式是用来对创建对象的细节进行封装的一种模式。

工厂模式分为三种:(1)简单工厂(静态工厂);(2)工厂方法;(3)抽象工厂。

  1. 简单工厂
    简单工厂并不是一个设计模式,而是一种编程习惯。它通过专门定义一个类来负责对象的创建,被创建的实例通常都具有共同的父类。这样做能把客户类和具体子类的实现解耦,客户类不再需要知道有哪些子类以及应当实例化哪个子类。

    假设现在有一个PizzaStore类,该店根据pizza名为客户提供pizza。此时如果在PizzaStore类完成具体pizza的创建,那么一旦pizza的类别发生了变化,就需要对PizzaStore类的代码进行修改,从而没有”对修改关闭”。因此我们可以将实例化具体类的代码抽离出来,使得它们不会干扰到应用的其它部分。(当然,这只是把问题转移到了另一个地方,以后如果有变化,还是要对这里的代码进行修改。但是因为在这里进行了封装,以后可以只修改这里的代码并且可以在多个地方使用)。

    public class PizzaStore {
    
        SimplePizzaFactory factory;
    
        public PizzaStore(SimplePizzaFactory factory) {
            this.factory = factory;
        }
    
        public Pizza orderPizza(String type){
            Pizza pizza = null;
            pizza = factory.createPizza(type);
    
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
    
            return pizza;
        }
    }
    public class SimplePizzaFactory {
    
        public Pizza createPizza(String type) {
            Pizza pizza = null;
            if(type.equals("cheese")) {
                pizza = new CheesePizza();
            } else if(type.equals("clam")) {
                pizza = new ClamPizza();
            } else if(type.equals("veggie")) {
                pizza = new VeggiePizza();
            }
    
            return pizza;
        }
    }
    public abstract class Pizza {
    
        public void prepare(){
    
        }
    
        public void bake(){
    
        }
    
        public void cut(){
    
        }
    
        public void box(){
    
        }
    }

    在这里我们将制造pizza的工厂SimplePizzaFactory注入到PizzaStore的构造器中,方便PizzaStore的方法来制造pizza。另外每一个具体的pizza子类都继承自Pizza类,这样可以使得系统更有弹性。

  2. 工厂方法
     工厂方法模式通过让子类决定该创建的对象是什么,来达到将对象创建的过程进行封装的目的。它定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到了子类。
    其一般包含以下四种角色:
    (1)创建者(Creator)类。这是个抽象创建者类。它实现了所有操纵产品的方法,但不实现工厂方法,让子类实现工厂方法来制作产品。
    (2)具体创建者(ConcreteCreator)类。实现工厂方法,从而实际制造出产品。
    (3)产品(Product)类。所有的具体产品都要实现这个接口(抽象类)。这样一来,使用这些产品的类就可以引用这个接口而不是具体类。
    (4)具体产品(ConcreteProduct)类。定义和实现一些关些产品的属性和方法。

    以生产小汽车为例。所有的车厂都有生产小汽车的功能。但是不同具体的车厂在制造小汽车时的细节是不一样的,因此我们需要在生产小汽车时可以根据不同的变化来负责创建正确种类的小汽车。因此正确的做法是在不同车厂的子类中实现自己的生产小汽车的方法。

    创建者类为:

    public abstract class CarFactory {
    
        public abstract Car createCar(String type);
    }

    具体创建者类有2个:

    public class NIOCarFactory extends CarFactory {
        @Override
        public Car createCar(String type) {
            if(type.equals("es6")) {
                return new NIOES6();
            } else if(type.equals("es8")) {
                return new NIOES8();
            }
            return null;
        }
    }
    public class XPFactory extends CarFactory{
        @Override
        public Car createCar(String type) {
            if(type.equals("p7")) {
                return new XP7();
            } else if(type.equals("p9")) {
                return new XP9();
            }
            return null;
        }
    }

    在具体的工厂中根据不同的type创建对应的小汽车。
    抽象产品类:

    public abstract class Car {
    }

    具体产品类(这里只写一个,其它类似):

    public class NIOES8 extends Car{
        @Override
        public String toString() {
            return "NIO ES8";
        }
    }

    在工厂方法模式中,客户端不需知道具体产品类的类名,只需知道创建具体产品的工厂类;对于抽象工厂类,只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象。这个模式符合“依赖倒置”原则,即要依赖抽象,不要依赖具体类。这个原则表明:不能让高层组件依赖低层组件,而且不敢高层或低层组件,两者都应该依赖抽象。在上面的例子中,CarFactory是高层组件,Car的具体子类则是低层组件。二者都依赖于Car这个抽象。
    依赖倒置原则的指导方针:
    (1)变量不可以持有具体类的引用。
    (2)不要让类派生自具体类。
    (3)不要覆盖基类中已实现的方法。

  3. 抽象工厂
    抽象工厂提供一个接口,用于创建相关或者是依赖对象的家族,而不需要明确指定具体类。这样一来,客户就从具体的产品中被解耦。而上面的工厂方法模式只能为制造某一类产品,但是每多一个产品类就会多一个工厂类,这样会造成类爆炸。

    假设现在有个ComputerStore类,该类根据不同的牌子卖出不同的Computer。

    public abstract class ComputerStore {
        abstract Computer sell(String type);
    }
    public abstract class Computer {
        Mouse mouse;
        KeyBoard keyBoard;
    }

    在Computer类中包含多个组件,如鼠标Mouse和Keyboard键盘,并且这些组件各自含有不同的牌子。因此如果使用工厂方法模式为每一个组件都设置一个工厂那么会创建出很多个工厂类,在这种情况下可以使用抽象工厂模式,即工厂中创建产品族。

    public abstract class ComputerIngredientFactory {
        abstract Mouse createMouse(String type);
        abstract KeyBoard createKeyBoard(String type);
    }
    public class LogitechIngredientFactory extends ComputerIngredientFactory{
        @Override
        Mouse createMouse(String type) {
            return new LogitechMouse();
        }
    
        @Override
        KeyBoard createKeyBoard(String type) {
            return new LogitechKeyBoard();
        }
    }

    可以看到在ComputerIngredientFactory接口中提供了创建Mouse和KeyBoard类的接口,然后在LogitechIngredientFactory中对其进行了实现。注意:LogitechMouse类和LogitechKeyBoard类分别继承自Mouse和KeyBoard抽象类。

    在使用时,将创建的工厂注入到具体类中,从而获取到工厂生产的不同组件。

    public class ThinkPadComputerStore extends ComputerStore{
        @Override
        Computer sell(String type) {
            ComputerIngredientFactory factory = new LogitechIngredientFactory();
            if(type.equals("x1")) {
                return new ThinkPadComputer(factory);
            }
            return null;
        }
    }
    public class ThinkPadComputer extends Computer{
    
        public ThinkPadComputer(ComputerIngredientFactory factory) {
            this.mouse = factory.createMouse("");
            this.keyBoard = factory.createKeyBoard("");
        }
    }

 

     可以看出,抽象工厂的方法经常以工厂方法的方式实现,工厂内的每一个方法都负责创建一个具体产品,同时利用抽象工厂的子类来提供这些具体子类的实现。 

  

原创文章,作者:ItWorker,如若转载,请注明出处:https://blog.ytso.com/289014.html

(0)
上一篇 2022年9月12日
下一篇 2022年9月12日

相关推荐

发表回复

登录后才能评论