模式設計之創建對象:工廠模式

簡單工廠模式中我們介紹了簡單工廠模式,提到了簡單工廠模式違背了開閉原則,而“工廠方法模式”是對簡單工廠模式的進一步抽象化,其好處是可以使系統在不修改原來代碼的情況下引進新的產品,即滿足開閉原則。

 

優點:

  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>

 

運行結果:

 

結論:

工廠方法模式和簡單工廠模式在定義上的不同是很明顯的。工廠方法模式的核心是一個抽象工廠類,而不像簡單工廠模式, 把核心放在一個實類上。工廠方法模式可以允許很多實的工廠類從抽象工廠類繼承下來, 從而可以在實際上成爲多個簡單工廠模式的綜合,從而推廣了簡單工廠模式。
工廠方法相比於簡單工廠模式的優點是增加一個產品,只需要增加一個具體工廠類和具體產品類,沒有修改原先的工廠類,符合開閉原則。缺點是客戶端的代碼會需要修改(簡單工廠模式的客戶端不需要修改),隨着產品的繼續增加,所要實現的類的個數也會隨之增大。

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