• 每天一个设计模式之工厂模式(无工厂、简单工厂、工厂方法、抽象工厂)


    工厂模式属于创建型模式,通常所说的工厂模式指工厂方法模式,而简单工厂(或者说静态工厂)不属于GoF设计模式。本文从无工厂模式谈起,讲解为何演化出一系列的工厂模式。

    一、无工厂模式

    假设需要绘制图表,这些图表包括柱状图、折线图、饼状图等,以及将来可能需要扩充的其他类型的图标。一个简单的写法,可以在一个类中用if…else或者switch…case来判断要绘制的图表,然后执行绘制方法。

    class Chart {
            private String type;
            
            public Chart(String type) {
                this.type = type;
            }
            
            public void draw() {
                if ("histogram".equals(this.type)) {
                    
                }
                else if ("pie".equals(this.type)) {
    
                }
                else if ("line".equals(this.type)) {
    
                }
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    显然,这不满足“单一职责”的原则,因为类的使用者和创建者混在一起。为解决这个问题,工厂模式出来了,先看简单工厂。

    二、简单工厂

    也被称为静态工厂方法模式,它有一个工厂类,提供了一个的静态方法用来产生不同的产品类。

    // 产品类接口
    public interface Chart {
        void draw();
    }
    
    // 具体的产品
    class PieChart implements Chart {
        public PieChart() {
            System.out.println("创建饼状图");
        }
    
        public void draw() {
            System.out.println("绘制饼状图");
        }
    }
    
    class HistogramChart implements Chart {
        public HistogramChart() {
            System.out.println("创建柱状图");
        }
    
        public void draw() {
            System.out.println("绘制柱状图");
        }
    }
    
    // 工厂类
    public class ChartFactory {
        public static Chart getChart(String type) {
            Chart chart = null;
            if (type.equalsIgnoreCase("HistogramChart")) {
                chart = new HistogramChart();
            }
            else if (type.equalsIgnoreCase("PieChart")) {
                chart = new PieChart();
            }
            return chart;
        }
    }
    
    // 客户类
    public class Client {
        public static void main(String[] args) {
            Chart pieChart = ChartFactory.getChart("PieChart");
            pieChart.draw();
            System.out.println("----------------");
            Chart hChart = ChartFactory.getChart("histogramchart");
            hChart.draw();
        }
    }
    
    /** 
    运行结果
    创建饼状图
    绘制饼状图
    ----------------
    创建柱状图
    绘制柱状图
    **/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    简单工厂模式,把产品类的创建逻辑都放在工厂类里面,实现了创建和使用隔离。但是,这还存在一个问题,它不满足“对修改关闭,对扩展开放”的原则。一旦需要增加产品类,就得在工厂类里面添加 if 分支修改工厂的创建逻辑。

    为了解决这个问题,工厂方法模式出现了。我们将工厂类进行改造,去掉创建方法的具体实现(一系列的 if…else),让其抽象化。具体的实现则由具体的工程类去完成。

    三、工厂方法

    // 产品类接口
    public interface Drawable {
        void draw();
    }
    // 工厂类接口
    public interface IChartFactory {
        Drawable createChart();
    }
    // 具体产品1
    public class LineChart implements Drawable {
        public LineChart() {
            System.out.println("创建折线图");
        }
    
        public void draw() {
            System.out.println("绘制折线图");
        }
    }
    // 具体产品2
    public class PieChart implements Drawable {
        public PieChart() {
            System.out.println("创建饼状图");
        }
    
        public void draw() {
            System.out.println("绘制饼状图");
        }
    }
    // 具体工厂1
    public class LineChartFactory implements IChartFactory {
        public Drawable createChart() {
            return new LineChart();
        }
    }
    // 具体工厂2
    public class PieChartFactory implements IChartFactory {
        public Drawable createChart() {
            return new PieChart();
        }
    }
    // 客户类
    public class Client {
        public static void main(String[] args) {
            Drawable chart1 = new LineChartFactory().createChart();
            chart1.draw();
    
            System.out.println("----------------");
    
            Drawable chart2 = new PieChartFactory().createChart();
            chart2.draw();
        }
    }
    // 运行结果
    /**
    创建折线图
    绘制折线图
    ----------------
    创建饼状图
    绘制饼状图
    **/
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60

    解决了静态工厂方法中存在的需要修改工厂类才能添加新的产品类的缺陷,但是现在又带来另一个问题,每添加一个产品类就得创建一个相应的工厂类,这带来了不少繁琐。如果要创建一系列的产品,比如手机产品,电脑产品,电视产品,同时每类产品下面又有不同的品牌。工厂方法模式遇到这种带有产品层级的问题时要发生类爆炸了。

    为了解决这个问题,抽象工厂模式出现了。

    四、抽象工厂

    // color 产品族接口
    public interface Colorful {
        void fill();
    }
    // shape 产品族接口
    public interface Drawable {
        void draw();
    }
    / ***以下是产品族具体类***/
    public class Blue implements Colorful {
        public void fill() {
            System.out.println("用蓝色填充");
        }
    }
    public class Red implements Colorful {
        public void fill() {
            System.out.println("用红色填充");
        }
    }
    public class LineChart implements Drawable {
        public LineChart() {
            System.out.println("创建折线图");
        }
    
        public void draw() {
            System.out.println("绘制折线图");
        }
    }
    public class PieChart implements Drawable {
        public PieChart() {
            System.out.println("创建饼状图");
        }
    
        public void draw() {
            System.out.println("绘制饼状图");
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    // 抽象工厂类,提供一个产品线的抽象方法
    public abstract class AbstractChartFactory {
        public abstract Colorful getColor(String color);
        public abstract Drawable getChart(String shape);
    }
    // color产品族工厂类
    public class ColorFactory extends AbstractChartFactory {
        public Colorful getColor(String color) {
            if ("red".equalsIgnoreCase(color))
                return new Red();
            if ("blue".equalsIgnoreCase(color))
                return new Blue();
            throw new RuntimeException();
        }
    
        public Drawable getChart(String shape) {
            return null;
        }
    }
    // shape产品族工厂类
    public class ChartFactory extends AbstractChartFactory {
        public Colorful getColor(String color) {
            return null;
        }
    
        public Drawable getChart(String shape) {
            if ("line".equalsIgnoreCase(shape))
                return new LineChart();
            if ("pie".equalsIgnoreCase(shape))
                return new PieChart();
            throw new RuntimeException();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    // 生产工厂类的工厂类
    public class FactoryProducer {
        public static AbstractChartFactory getFactory(String choice) {
            if (choice.equalsIgnoreCase("shape"))
                return new ChartFactory();
            if (choice.equalsIgnoreCase("color"))
                return new ColorFactory();
            throw new RuntimeException();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    // 客户类
    public class Client {
        public static void main(String[] args) {
            AbstractChartFactory shapeFactory = FactoryProducer.getFactory("shape");
            Drawable line = shapeFactory.getChart("line");
            line.draw();
    
            System.out.println("----------------");
    
            AbstractChartFactory shapeFactory2 = FactoryProducer.getFactory("shape");
            Drawable pie = shapeFactory.getChart("pie");
            pie.draw();
    
            System.out.println("----------------");
    
            AbstractChartFactory colorFactory = FactoryProducer.getFactory("color");
            Colorful red = colorFactory.getColor("red");
            red.fill();
    
            System.out.println("----------------");
    
            AbstractChartFactory colorFactory2 = FactoryProducer.getFactory("color");
            Colorful blue = colorFactory.getColor("blue");
            blue.fill();
        }
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    运行结果:
    
    创建折线图
    绘制折线图
    ----------------
    创建饼状图
    绘制饼状图
    ----------------
    用红色填充
    ----------------
    用蓝色填充
    
    Process finished with exit code 0
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    其实,我也不知道实际开发中有哪里有用到抽象工厂类,有空了需要去找一下框架代码中的具体例子。
    // todo,阅读Spring 源码。

    五、参考

    1. https://www.codeproject.com/articles/716413/factory-method-pattern-vs-abstract-factory-pattern
    2. https://stackoverflow.com/questions/13029261/design-patterns-factory-vs-factory-method-vs-abstract-factory
    3. https://www.runoob.com/design-pattern/factory-pattern.html
    4. https://www.runoob.com/design-pattern/abstract-factory-pattern.html
    5. 《设计模式 Java版本》 ,作者 进击的皇虫
  • 相关阅读:
    前端实现生成图片并批量下载,下载成果物是zip包
    让你说一说Sass、Less 的区别是什么,你知道吗?
    Compose 动画
    python中的上下文管理器
    C++学习笔记(一)
    神经网络与深度学习入门必备知识|概论
    管理会计习题集及答案 1-4章
    [计算机提升] 计算机系统中的格式化
    软件测试技术之单元测试—工程师 Style 的测试方法(2)
    vue事件处理&&表单输入绑定
  • 原文地址:https://blog.csdn.net/M_sdn/article/details/126259649