<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                **工廠方法模式** 是一種創建型設計模式,其在父類中提供一個創建對象的方法,允許子類決定實例化對象的類型。 ***** &nbsp; 假設你正在開發一款物流管理應用。最初版本只能處理卡車 運輸,因此大部分代碼都在位于名為 卡車 的類中。 一段時間后,這款應用變得極受歡迎。你每天都能收到十幾 次來自海運公司的請求,希望應用能夠支持海上物流功能。 ![](images/1_1636251660415.png) 如果代碼其余部分與現有類已經存在耦合關系,那么向程序 中添加新類其實并沒有那么容易。 這可是個好消息。但是代碼問題該如何處理呢?目前,大部 分代碼都與 卡車 類相關。在程序中添加 輪船 類需要修改 全部代碼。更糟糕的是,如果你以后需要在程序中支持另外 一種運輸方式,很可能需要再次對這些代碼進行大幅修改。 &nbsp; 最后,你將不得不編寫繁復的代碼,根據不同的運輸對象類, 在應用中進行不同的處理。 ***** **解決方案** 工廠方法模式建議使用特殊的工廠方法代替對于對象構造函 數的直接調用(即使用 new 運算符)。不用擔心,對象仍將 通過 new 運算符創建,只是該運算符改在工廠方法中調用 罷了。工廠方法返回的對象通常被稱作“產品”。 ![](images/1_1636251786022.png) 子類可以修改工廠方法返回的對象類型。 乍看之下,這種更改可能毫無意義:我們只是改變了程序中 調用構造函數的位置而已。但是,仔細想一下,現在你可以 在子類中重寫工廠方法,從而改變其創建產品的類型。 &nbsp; 但有一點需要注意:僅當這些產品具有共同的基類或者接口 時,子類才能返回不同類型的產品,同時基類中的工廠方法 還應將其返回類型聲明為這一共有接口。 ![](images/1_1636252140282.png) 所有產品都必須使用同一接口。 舉例來說, 卡車 Truck 和 輪船 Ship 類都必須實現 運輸 Transport 接口, 該接口聲明了一個名為 deliver 交 付 的 方 法。 每 個 類 都 將 以 不 同 的 方 式 實 現 該 方 法: 卡 車 走 陸 路 交 付 貨 物, 輪 船 走 海 路 交 付 貨 物。 陸路運輸 RoadLogistics 類中的工廠方法返回卡車對象,而 海路運輸 SeaLogistics 類則返回輪船對象。 ![](images/1_1636252991360.png) 調用工廠方法的代碼(通常被稱為客戶端代碼)無需了解不 同子類返回實際對象之間的差別。客戶端將所有產品視為抽 象的 運輸 。 客戶端知道所有運輸對象都提供 交付 方法, 但是并不關心其具體實現方式。 ***** ![](images/1_1636253019808.png) 1. 產品(Product)將會對接口進行聲明。對于所有由創建者及其子類構建的對象,這些接口都是通用的。 2. 具體產品(Concrete Products)是產品接口的不同實現。 3. 創建者(Creator)類聲明返回產品對象的工廠方法。該方法的返回對象類型必須與產品接口相匹配。 你可以將工廠方法聲明為抽象方法,強制要求每個子類以不同方式實現該方法。或者,你也可以在基礎工廠方法中返回默認產品類型。 &nbsp; 注意,盡管它的名字是創建者,但他最主要的職責并不是創建產品。一般來說,創建者類包含一些與產品相關的核心業務邏輯。 &nbsp; 工廠方法將這些邏輯處理從具體產品類中分離出來。打個比方,大型軟件開發公司擁有程序員培訓部門。但是,這些公司的主要工作還是編寫代碼,而非生產程序員。 4. 具體創建者(Concrete Creators) 將會重寫基礎工廠方法,使其返回不同類型的產品。注意,并不一定每次調用工廠方法都會創建新的實例。工廠 方法也可以返回緩存、對象池或其他來源的已有對象。 ***** ### **代碼示例** JAVA版: ## 生成跨平臺的 GUI 元素 在本例中,按鈕擔任產品的角色,對話框擔任創建者的角色。 不同類型的對話框需要其各自類型的元素。因此我們可為每個對話框類型創建子類并重寫其工廠方法。 現在,每種對話框類型都將對合適的按鈕類進行初始化。對話框基類使用其通用接口與對象進行交互,因此代碼更改后仍能正常工作。 buttons/Button.java: 通用產品接口 ``` package design_pattern.factory_method.example.buttons; /** * Common interface for all buttons. */ public interface Button { void render(); void onClick(); } ``` buttons/HtmlButton.java: 具體產品 ``` package design_pattern.factory_method.example.buttons; /** * HTML button implementation. */ public class HtmlButton implements Button { public void render() { System.out.println("<button>Test Button</button>"); onClick(); } public void onClick() { System.out.println("Click! Button says - 'Hello World!'"); } } ``` buttons/WindowsButton.java: 另一個具體產品 ``` package design_pattern.factory_method.example.buttons; import javax.swing.*; import java.awt.*; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; /** * Windows button implementation. */ public class WindowsButton implements Button { JPanel panel = new JPanel(); JFrame frame = new JFrame(); JButton button; public void render() { frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); JLabel label = new JLabel("Hello World!"); label.setOpaque(true); label.setBackground(new Color(235, 233, 126)); label.setFont(new Font("Dialog", Font.BOLD, 44)); label.setHorizontalAlignment(SwingConstants.CENTER); panel.setLayout(new FlowLayout(FlowLayout.CENTER)); frame.getContentPane().add(panel); panel.add(label); onClick(); panel.add(button); frame.setSize(320, 200); frame.setVisible(true); onClick(); } public void onClick() { button = new JButton("Exit"); button.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { frame.setVisible(false); System.exit(0); } }); } } ``` factory/Dialog.java: 基礎創建者 ``` package design_pattern.factory_method.example.factory; import design_pattern.factory_method.example.buttons.Button; /** * Base factory class. Note that "factory" is merely a role for the class. It * should have some core business logic which needs different products to be * created. */ public abstract class Dialog { public void renderWindow() { // ... other code ... Button okButton = createButton(); okButton.render(); } /** * Subclasses will override this method in order to create specific button * objects. */ public abstract Button createButton(); } ``` factory/HtmlDialog.java: 具體創建者 ``` package design_pattern.factory_method.example.factory; import design_pattern.factory_method.example.buttons.Button; import design_pattern.factory_method.example.buttons.HtmlButton; /** * HTML Dialog will produce HTML buttons. */ public class HtmlDialog extends Dialog { @Override public Button createButton() { return new HtmlButton(); } } ``` factory/WindowsDialog.java: 另一個具體創建者 ``` package design_pattern.factory_method.example.factory; import design_pattern.factory_method.example.buttons.Button; import design_pattern.factory_method.example.buttons.WindowsButton; /** * Windows Dialog will produce Windows buttons. */ public class WindowsDialog extends Dialog { @Override public Button createButton() { return new WindowsButton(); } } ``` Demo.java: 客戶端代碼 ``` package design_pattern.factory_method.example; import design_pattern.factory_method.example.factory.Dialog; import design_pattern.factory_method.example.factory.HtmlDialog; import design_pattern.factory_method.example.factory.WindowsDialog; /** * Demo class. Everything comes together here. */ public class Demo { private static Dialog dialog; public static void main(String[] args) { configure(); runBusinessLogic(); } /** * The concrete factory is usually chosen depending on configuration or * environment options. */ static void configure() { if (System.getProperty("os.name").equals("Windows 10")) { dialog = new WindowsDialog(); } else { dialog = new HtmlDialog(); } } /** * All of the client code should work with factories and products through * abstract interfaces. This way it does not care which factory it works * with and what kind of product it returns. */ static void runBusinessLogic() { dialog.renderWindow(); } } ``` OutputDemo.txt: 執行結果 (Html-Dialog) ``` <button>Test Button</button> Click! Button says - 'Hello World!' ``` ![](https://img.kancloud.cn/65/bd/65bd7e18262a1a19ff241c4477f63b66_306x193.png) ***** PHP版: ``` <?php /** * Factory Method Design Pattern * * Intent: Provides an interface for creating objects in a superclass, but * allows subclasses to alter the type of objects that will be created. * * Example: In this example, the Factory Method pattern provides an interface * for creating social network connectors, which can be used to log in to the * network, create posts and potentially perform other activities—and all of * this without coupling the client code to specific classes of the particular * social network. */ /** * The Creator declares a factory method that can be used as a substitution for * the direct constructor calls of products, for instance: * * - Before: $p = new FacebookConnector(); * - After: $p = $this->getSocialNetwork; * * This allows changing the type of the product being created by * SocialNetworkPoster's subclasses. */ abstract class SocialNetworkPoster { /** * The actual factory method. Note that it returns the abstract connector. * This lets subclasses return any concrete connectors without breaking the * superclass' contract. */ abstract public function getSocialNetwork(): SocialNetworkConnector; /** * When the factory method is used inside the Creator's business logic, the * subclasses may alter the logic indirectly by returning different types of * the connector from the factory method. */ public function post($content): void { // Call the factory method to create a Product object... $network = $this->getSocialNetwork(); // ...then use it as you will. $network->logIn(); $network->createPost($content); $network->logout(); } } /** * This Concrete Creator supports Facebook. Remember that this class also * inherits the 'post' method from the parent class. Concrete Creators are the * classes that the Client actually uses. */ class FacebookPoster extends SocialNetworkPoster { private $login, $password; public function __construct(string $login, string $password) { $this->login = $login; $this->password = $password; } public function getSocialNetwork(): SocialNetworkConnector { return new FacebookConnector($this->login, $this->password); } } /** * This Concrete Creator supports LinkedIn. */ class LinkedInPoster extends SocialNetworkPoster { private $email, $password; public function __construct(string $email, string $password) { $this->email = $email; $this->password = $password; } public function getSocialNetwork(): SocialNetworkConnector { return new LinkedInConnector($this->email, $this->password); } } /** * The Product interface declares behaviors of various types of products. */ interface SocialNetworkConnector { public function logIn(): void; public function logOut(): void; public function createPost($content): void; } /** * This Concrete Product implements the Facebook API. */ class FacebookConnector implements SocialNetworkConnector { private $login, $password; public function __construct(string $login, string $password) { $this->login = $login; $this->password = $password; } public function logIn(): void { echo "Send HTTP API request to log in user $this->login with " . "password $this->password\n"; } public function logOut(): void { echo "Send HTTP API request to log out user $this->login\n"; } public function createPost($content): void { echo "Send HTTP API requests to create a post in Facebook timeline.\n"; } } /** * This Concrete Product implements the LinkedIn API. */ class LinkedInConnector implements SocialNetworkConnector { private $email, $password; public function __construct(string $email, string $password) { $this->email = $email; $this->password = $password; } public function logIn(): void { echo "Send HTTP API request to log in user $this->email with " . "password $this->password\n"; } public function logOut(): void { echo "Send HTTP API request to log out user $this->email\n"; } public function createPost($content): void { echo "Send HTTP API requests to create a post in LinkedIn timeline.\n"; } } /** * The client code can work with any subclass of SocialNetworkPoster since it * doesn't depend on concrete classes. */ function clientCode(SocialNetworkPoster $creator) { // ... $creator->post("Hello world!"); $creator->post("I had a large hamburger this morning!"); // ... } /** * During the initialization phase, the app can decide which social network it * wants to work with, create an object of the proper subclass, and pass it to * the client code. */ echo "Testing ConcreteCreator1:\n"; clientCode(new FacebookPoster("john_smith", "******")); echo "\n\n"; echo "Testing ConcreteCreator2:\n"; clientCode(new LinkedInPoster("john_smith@example.com", "******")); ```
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看