• 工厂方法模式


    简单工厂模式 | 偷掉月亮 (moonshuo.cn)
    原文链接:工厂方法模式 | 偷掉月亮 (moonshuo.cn)

    工厂方法模式概述

    在面对简单工厂模式的时候,如果此时我们工厂生产圆形和椭圆形纽扣,那么此时我们可以通过一个简单的工厂进行生产,但是如果此时我们想要进行正方形或者长方形的工厂生产,那么此时我们不得不进行源代码的修改,那么此时就违背了开闭原则,而且当我们再一次需要生产圆形的纽扣,那么还得更改过来。

    那么解决方法就是在开一个新的厂子,那么现在我们有圆形纽扣工厂和方形纽扣工厂,那么还是存在一个问题,如果我想要生产⭐型扣子,那么我们还需要建立一个工厂,那么此时我们可以对这个工厂进行抽象为一个父类

    工厂方法模式(虚拟构造器模式或者多态构造模式):定义一个用于创建对象的接口,但是让子类决定将哪一个类进行实例化,工厂方法模式让一个类的实例化延迟到了子类

    举例

    这里表示一个button的类,如果没有共同的代码,可以转换为接口,降低耦合度

    package 设计模式.工厂模式;
    
    /**
     * @author zss
     * @date 2022-07-27 11:39:14
     * @description 所有扣子的抽象类
     */
    public abstract class Button {
        /**表示进行扣子规格的操作 */
        public  void buttonSpecification(){
            System.out.println("正在进行定制中");
        };
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    这里时圆形扣子的制作

    public class RoundButton extends Button {
        @Override
        public void buttonSpecification() {
            super.buttonSpecification();
            System.out.println("这是一个圆形扣子,需要满足圆形的定义");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    这里是方形扣子的制作

    package 设计模式.工厂模式;
    
    /**
     * @author zss
     * @date 2022-07-27 11:46:08
     * @description
     */
    public class SquareButton extends Button{
        @Override
        public void buttonSpecification() {
            super.buttonSpecification();
            System.out.println("这是一个方形扣子,需要满足相应的条件");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    下面是一个抽象的工厂接口类

    package 设计模式.工厂模式;
    
    /**
     * @author zss
     * @date 2022-07-27 11:31:11
     * @description 所有工厂的抽象
     */
    public interface ButtonFactory {
        /**表示每一个子类工厂创建对象的方式*/
        public Button factoryMethod();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    这里是一个圆形扣子的生产方式

    package 设计模式.工厂模式;
    
    /**
     * @author zss
     * @date 2022-07-27 11:33:29
     * @description 用于生产圆形扣子的工厂
     */
    public class RoundButtonFactory implements ButtonFactory {
        @Override
        public Button factoryMethod() {
            return new RoundButton();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    方形扣子的生产方式

    package 设计模式.工厂模式;
    
    /**
     * @author zss
     * @date 2022-07-27 11:50:05
     * @description
     */
    public class SquareButtonFactory implements ButtonFactory{
        @Override
        public Button factoryMethod() {
            return new SquareButton();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    客户

    package 设计模式.工厂模式;
    
    import 设计模式.简单工厂模式.example1.Factory;
    
    /**
     * @author zss
     * @date 2022-07-27 11:50:38
     * @description 客户
     */
    public class Client {
        public static void main(String[] args) {
            Factory factory;
            Button button;
            //客户需要圆形扣子,经过一系列的判断,得到下面的例子
            Button button1=new RoundButton();
            button1.buttonSpecification();
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    优化1

    其实这里的用户应该传输过来一个清单,我们根据清单的内容进行判断,返回创建的对象内容

    
    <demand>
        <button>圆形button>
        <button>方形button>
        <button>星星button>
    demand>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    package 设计模式.工厂模式;
    
    import org.w3c.dom.*;
    import org.xml.sax.SAXException;
    
    import javax.xml.parsers.*;
    import java.io.*;
    import java.util.LinkedList;
    import java.util.List;
    
    
    /**
     * @author zss
     * @date 2022-07-25 20:30:01
     * @description 此方法用于从xml文件中读取配置
     */
    public class XMLUtil {
        public static List getFruitType() {
            try {
                List list=new LinkedList<>();
                DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
                Document doc = (Document) dBuilder.parse(new File("D:\\算法\\src\\设计模式\\工厂模式\\demand.xml"));
                NodeList n1 = doc.getElementsByTagName("button");
                //在这里如果一次性得到很多的节点,那么使用for循环进行操作,同时工厂中也可以使用for循环
                for (int i = 0; i < n1.getLength(); i++) {
                    Node classNode = n1.item(i).getFirstChild();
                    String fruitType = classNode.getNodeValue().trim();
                    list.add(fruitType);
                }
                return list;
    
            } catch (ParserConfigurationException | SAXException | IOException e) {
                e.printStackTrace();
                return null;
            }
        }
    }
    
    • 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
    package 设计模式.工厂模式;
    
    import 设计模式.简单工厂模式.example1.Factory;
    
    /**
     * @author zss
     * @date 2022-07-27 11:50:38
     * @description 客户
     */
    public class Client {
        public static void main(String[] args) {
            ButtonFactory buttonFactory;
            Button button ;
            for (String b : XMLUtil.getFruitType()) {
                if (b.equals("圆形")) {
                    button = new RoundButtonFactory().factoryMethod();
                    button.buttonSpecification();
                } else if (b.equals("方形")) {
                    button=new SquareButtonFactory().factoryMethod();
                    button.buttonSpecification();
                }else {
                    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

    image-20220727121433269

    这样我们可以根据用户的订单大量的生产东西,

    优化2

    上面虽然实现了对用户订单的批量处理,但是我们发现如果现在工厂已经增加了可以生产其他图形的类别,那么我就需要在Client中添加多个代码,那么反而又需要我们进行代码的修改,这样反而违反了开闭原则,我们希望我们这个也可以在xml文件中进行配置。但是可惜的是工厂不像用户清单那样,只需要获得字符串就好,这里需要我们与类进行关联,那么我们就不得不使用到反射

    
    <config>
        <buttonType type="圆形" className="设计模式.工厂模式.RoundButtonFactory"/>
        <buttonType type="方形" className="设计模式.工厂模式.SquareButtonFactory"/>
    config>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    package 设计模式.工厂模式;
    
    import org.w3c.dom.Document;
    import org.w3c.dom.Element;
    import org.w3c.dom.Node;
    import org.w3c.dom.NodeList;
    
    import javax.xml.parsers.DocumentBuilder;
    import javax.xml.parsers.DocumentBuilderFactory;
    import java.io.File;
    
    /**
     * @author zss
     * @date 2022-07-28 17:11:40
     * @description 读取工厂xml文件的方法,我们需要他返回一个真正的实例
     */
    public class XMLFactoryUtil {
        public static ButtonFactory getFactory(String buttonType) {
            try {
                DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
                DocumentBuilder dBuilder = dFactory.newDocumentBuilder();
                Document doc = (Document) dBuilder.parse(new File("D:\\算法\\src\\设计模式\\工厂模式\\classConfig.xml"));
                NodeList n1 = doc.getElementsByTagName("buttonType");
                String factoryType = null;
                for (int i = 0; i < n1.getLength(); i++) {
                    //得到第一个节点的值,即那个圆形,方形等信息
                    Node node=n1.item(i);
                    Element element=(Element) node;
                    String button = element.getAttribute("type").trim();
                    if (buttonType.equals(button)){
                        factoryType=element.getAttribute("className");
                        break;
                    }
                }
                Class c = Class.forName(factoryType);
                Object o = c.newInstance();
                return (ButtonFactory) o;
            } catch (Exception e) {
                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
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    package 设计模式.工厂模式;
    
    /**
     * @author zss
     * @date 2022-07-27 11:50:38
     * @description 客户
     */
    public class Client {
        public static void main(String[] args) {
            ButtonFactory buttonFactory;
            Button button ;
            for (String b : XMLUtil.getFruitType()) {
                buttonFactory=XMLFactoryUtil.getFactory(b);
                button=buttonFactory.factoryMethod();
                button.buttonSpecification();
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    image-20220728180917344

    是不是很像Spring!!!

    总结

    当然我们还可以进一步对这个代码进行优化,比如将创建工厂的方法隐藏,因为客户不需要知道你的工厂是怎么创建的,只需要将这个创建的方法移动到创建图形的时候,或者我们也可以提前将这个创建的对象存储到容器中(和spring一样,但是我们可以存储在map中),这些实际的方法都可以进行。

    优点:

    1. 扩展性高,新的产品来的时候,我们可以直接添加产品细节和工厂建造
    2. 完全对外部隐藏了创建的细节,客户不知道工厂怎么创建的,但是知道有这个工厂,而且客户的产品也可以准确生产,而且客户也不需要知道生产过程

    缺点:

    1. 引入抽象层,可理解性变差
  • 相关阅读:
    Neuron v2.2.2 发布:MQTT插件功能提升 、新增OPC DA驱动
    1541_AURIX_TriCore内核架构_内核调试控制器CDC
    【linux】进程
    根文件系统制作并启动 Linux
    ADC的数据读取问题
    项目实战第十七讲:使用异步编排优化商品详情页(对外流量最大)
    [ACNOI2022]不是构造,胜似构造
    三年精进笃行,用友YonSuite“数智飞轮”高速运转起来了!
    有哪些适用于 Windows 的PDF 阅读器?免费 PDF 阅读器清单
    [含文档+PPT+源码等]精品基于Uniapp+SSM实现的Android的校园新闻管理系统实现的App[包运行成功]计算机毕业设计Android项目源码
  • 原文地址:https://blog.csdn.net/qq_58510930/article/details/126123058