设计模式之工厂模式

257 阅读6分钟

开始

23种设计模式可分为创建型模式、结构型模式和行为型模式 3 种。

1.创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例、原型、工厂方法、抽象工厂、建造者等 5 种创建型模式。

2.结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。

3.行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种行为型模式。

GoF又称 Gang of Four,即 Erich Gamma, Richard Helm, Ralph Johnson & John Vlissides,软件设计领域的四位大师。

开闭原则

所谓面向对象的开放-封闭原则,就是在程序中对“扩展”开放,对“修改”封闭。如果每次业务改动都要增加新的if-else,就涉及对旧有代码的修改,不但容易出错,可读性也不好。

原理

工厂模式又分为简单工厂模式和工厂方法模式,抽象工厂模式三种

1.简单工厂模式

定义一个工厂类,根据传入的参数不同返回不同的实例,被创建的实例具有共同的父类或接口。但是严格来说,简单工厂并不是一个设计模式,它只是人们的一种编码习惯,且它也违背了开闭原则。

适用场景

(1)需要创建的对象较少

(2)客户端不需要关心对象的创建过程。

其UML类图如下:

代码示例

Basketball:篮球类规范接口((AbstractProduct))

public interface Basketball {
    /**
     * 操作工厂接口
     */
    void make();
}

Spalding类:制造斯伯丁篮球(Product1)

public class Spalding implements Basketball {
    public Spalding() {
        this.make();
    }

    @Override
    public void make() {
        System.out.println("制造斯伯丁篮球");
    }
}

Nike类:制造耐克篮球(Product2)

public class Nike implements Basketball {

    public Nike() {
        this.make();
    }

    @Override
    public void make() {
        System.out.println("制造耐克篮球");
    }
}

BasketballFactory类:篮球代工厂(Factory)

public class BasketballFactory {
    public Basketball makeBasketball(String basketballType) {
        if ("Spalding".equalsIgnoreCase(basketballType)) {
            return new Spalding();
        } else if ("Nike".equalsIgnoreCase(basketballType)) {
            return new Nike();
        }
        return null;
    }
}

测试类:

2.工厂方法模式

(英语:Factory method pattern)是一种实现了“工厂”概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是“定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。”[1]

适用场景:

  (1)客户端不需要知道它所创建的对象的类。例子中我们不知道每个图片加载器具体叫什么名,只知道创建它的工厂名就完成了创建过程。    (2)客户端可以通过子类来指定创建对应的对象。

从上图可以看出,使用工厂方法模式涉及到以下角色:

抽象工厂(AbstractFactory)角色:担任这个角色的是工厂方法模式的核心,任何在模式中创建对象的工厂类必须实现这个接口。在实际的系统中,这个角色也常常使用抽象类实现。

具体工厂(ConcreteFactory1、ConcteteFactory2)角色:担任这个角色的是实现了抽象工厂接口的具体JAVA类。具体工厂角色含有与业务密切相关的逻辑,并且受到使用者的调用以创建导出类。

抽象产品(AbstractProduct)角色:工厂方法模式所创建的对象的超类,也就是所有球类的共同父类或共同拥有的接口。在实际的系统中,这个角色也常常使用抽象类实现。

具体产品(product等)角色:这个角色实现了抽象球类角色所声明的接口,工厂方法模式所创建的每一个对象都是某个具体球类的实例。

代码示例:

其中和产品相关的Basketball类、Spalding类和Nike类的定义不变。

AbstractFactory类:生产不同产品的工厂的抽象类

public interface AbstractFactory {
    /**
     * 工厂类
     *
     * @return
     */
    public Basketball makeBasketball();
}

NikeFactory类:生产耐克篮球的工厂(ConcreteFactory1)

public class NikeFactory implements AbstractFactory {
    @Override
    public Basketball makeBasketball() {
        return new Nike();
    }
}

SpaldingFactory类:生产斯伯丁篮球的工厂(ConcreteFactory2)

public class SpaldingFactory implements AbstractFactory {
    @Override
    public Basketball makeBasketball() {
        return new Spalding();
    }
}

测试类:

3. 抽象工厂模式(Abstract Factory)

上面两种模式不管工厂怎么拆分抽象,都只是针对一类产品Basketball(Product),如果要生成另一种产品象棋,应该怎么表示呢?

抽象工厂模式通过在AbstarctFactory中增加创建产品的接口,并在具体子工厂中实现新加产品的创建,当然前提是子工厂支持生产该产品。否则继承的这个接口可以什么也不干。

适用场景:

(1)和工厂方法一样客户端不需要知道它所创建的对象的类。

(2)需要一组对象共同完成某种功能时。并且可能存在多组对象完成不同功能的情况。

(3)系统结构稳定,不会频繁的增加对象。(因为一旦增加就需要修改原有代码,不符合开闭原则)

其UML类图如下:

从上面类图结构中可以清楚的看到如何在工厂方法模式中通过增加新产品接口来实现产品的增加的。

代码示例:

Chess类:定义象棋产品的接口(AbstractChess)

public interface Chess {
    void make();
}

NikeChess类:假设耐克生产的象棋(NikeChess)

public class NikeChess implements Chess {
    public NikeChess() {
        this.make();
    }
    @Override
    public void make() {
        
        System.out.println("make NikeChess!");
    }
}

SpaldingChess类:假设斯伯丁生产的象棋(SpaldingChess)

public class SpaldingChess implements Chess {
    public SpaldingChess() {
        this.make();
    }
    @Override
    public void make() {
        System.out.println("make SpaldingChess!");
    }
}

下面需要修改工厂相关的类的定义:

AbstractFactory类:增加Chess产品制造接口

public interface AbstractFactory {
    /**
     * 工厂类
     *
     * @return
     */
    public Basketball makeBasketball();
    
    public Chess makeChess();
}

NikeFactory类:增加耐克象棋的制造(ConcreteFactory1)

public class NikeFactory implements AbstractFactory {
    @Override
    public Basketball makeBasketball() {
        return new Nike();
    }

    @Override
    public Chess makeChess() {
        return new NikeChess();
    }
}

SpaldingFactory类:增加斯伯丁象棋的制造(ConcreteFactory2)

public class SpaldingFactory implements AbstractFactory {
    @Override
    public Basketball makeBasketball() {
        return new Spalding();
    }

    @Override
    public Chess makeChess() {
        return new SpaldingChess();
    }
}

测试类:

public class BasketballTest {
    public static void main(String[] args) {
        NikeFactory nikeFactory = new NikeFactory();
        SpaldingFactory spaldingFactory = new SpaldingFactory();
        nikeFactory.makeBasketball();
         nikeFactory.makeChess();
        spaldingFactory.makeBasketball();
        spaldingFactory.makeChess();
    }
}

最后:

无论哪种工厂模式,都有它的长处和弊端,如有错误请指出,这就是本人对工厂设计模式的全部总结。