模式设计之创建对象:工厂模式

简单工厂模式中我们介绍了简单工厂模式,提到了简单工厂模式违背了开闭原则,而“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。

 

优点:

  1. 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
  2. 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
  3. 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。

缺点:

  1. 类的个数容易过多,增加复杂度
  2. 增加了系统的抽象性和理解难度
  3. 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。

应用场景:

  1. 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
  2. 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
  3. 客户不关心创建产品的细节,只关心产品的品牌

 

结构

  1. 工厂接口:提供了创建产品的接口,调用者通过它访问具体工厂的工厂方法 createProduct() 来创建产品。
  2. 具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。
  3. 产品接口:定义了产品的规范,描述了产品的主要特性和功能。
  4. 具体产品:实现了抽象产品角色所定义的接口,由具体工厂来创建,它同具体工厂之间一一对应。

UML关系图:

 

代码实现

文件结构:

工厂接口:

package factory;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 21:02
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public interface AnimalFarm {

    Animal createAnimal();
}

 

具体工厂:主要是实现抽象工厂中的抽象方法,完成具体产品的创建。

package factory;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 21:03
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public class CattleFarm implements AnimalFarm {

    @Override
    public Animal createAnimal() {
        System.out.println("新牛出生!");
        return new Cattle();
    }
}
package factory;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 21:02
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public class HorseFarm implements AnimalFarm {

    @Override
    public Animal createAnimal() {
        System.out.println("新马出生!");
        return new Horse();
    }
}

 

产品接口:

package factory;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 20:59
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public interface Animal {

    void show();
}

 

具体产品

package factory;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 21:01
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public class Cattle implements Animal {

    JScrollPane sp;
    JFrame jf = new JFrame("工厂方法模式测试");
    public Cattle() {
        Container contentPane = jf.getContentPane();
        JPanel p1 = new JPanel();
        p1.setLayout(new GridLayout(1, 1));
        p1.setBorder(BorderFactory.createTitledBorder("动物:牛"));
        sp = new JScrollPane(p1);
        contentPane.add(sp, BorderLayout.CENTER);
        JLabel l1 = new JLabel(new ImageIcon("src/factory/res/A_Cattle.jpg"));
        p1.add(l1);
        jf.pack();
        jf.setVisible(false);

        //用户点击窗口关闭
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
    }
    
    @Override
    public void show() {
        jf.setVisible(true);
    }
}

 

package factory;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.GridLayout;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 21:00
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public class Horse implements Animal {

    JScrollPane sp;
    JFrame jf = new JFrame("工厂方法模式测试");
    
    public Horse() {
        Container contentPane = jf.getContentPane();
        JPanel p1 = new JPanel();
        p1.setLayout(new GridLayout(1, 1));
        p1.setBorder(BorderFactory.createTitledBorder("动物:马"));
        sp = new JScrollPane(p1);
        contentPane.add(sp, BorderLayout.CENTER);
        JLabel l1 = new JLabel(new ImageIcon("src/factory/res/A_Horse.jpg"));
        p1.add(l1);
        jf.pack();
        jf.setVisible(false);

        //用户点击窗口关闭
        jf.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);    
    }
    
    @Override
    public void show() {
        jf.setVisible(true);
    }
}

 

配置类:

package factory;

import javax.xml.parsers.*;
import org.w3c.dom.*;
import java.io.*;

/**************************************************************************************************
 @Copyright 2003-2022
 @package factory
 @date 2022/2/4 21:11
 @author qiao wei
 @version 1.0
 @brief
 @history
 *************************************************************************************************/
public class ReadXML2 {

    public static Object getObject() {
        try {
            DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
            DocumentBuilder builder = dFactory.newDocumentBuilder();
            Document doc;
            doc = builder.parse(new File("src/factory/res/config2.xml"));
            NodeList nl = doc.getElementsByTagName("className");
            Node classNode = nl.item(0).getFirstChild();
            String cName = "factory." + classNode.getNodeValue();
            System.out.println("新类名:" + cName);
            Class<?> c = Class.forName(cName);
            Object obj = c.newInstance();
            return obj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
}

 

资源文件:

   

 

xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<config>
	<className>CattleFarm</className>
</config>

 

运行结果:

 

结论:

工厂方法模式和简单工厂模式在定义上的不同是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式可以允许很多实的工厂类从抽象工厂类继承下来, 从而可以在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。
工厂方法相比于简单工厂模式的优点是增加一个产品,只需要增加一个具体工厂类和具体产品类,没有修改原先的工厂类,符合开闭原则。缺点是客户端的代码会需要修改(简单工厂模式的客户端不需要修改),随着产品的继续增加,所要实现的类的个数也会随之增大。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章