[设计模式]工厂方法模式

简介

工厂方法模式 (Factory Method)定义一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化延迟到其他子类。 

工厂模式是一种类创建型模式可参考 设计模式 创建型模式)。

结构

图-工厂方法模式结构图

Product : 定义产品对象的接口。

abstract class Product {
 public abstract void Use();
 }

ConcreteProduct : 实现 Product 接口。

class ConcreteProduct extends Product {
 public ConcreteProduct() {
         System.out.println("创建 ConcreteProduct 产品");
     }
 
     @Override
 public void Use() {
         System.out.println("使用 ConcreteProduct 产品");
     }
 }

Creator : 声明工厂方法,它会返回一个产品类型的对象Creator 也可以实现一个默认的工厂方法 FactoryMethod() ,以返回一个默认的具体产品类型。

interface Creator {
 public Product FactoryMethod();
 }

ConcreteCreator : 覆写 Creator 中的工厂方法 FactoryMethod()

class ConcreteCreator implements Creator {
     @Override
 public Product FactoryMethod() {
 return new ConcreteProduct();
     }
 }

测试代码

public class FactoryMethodPattern {
 public static void main(String[] args) {
         Creator factory = new ConcreteCreator();
         Product product = factory.FactoryMethod();
         product.Use();
     }
 }

运行结果

创建 ConcreteProduct 产品
使用 ConcreteProduct 产品

动机

当一个类不知道它所必须创建的对象的类的时候。 当一个类希望由它的子类来指定它所创建的对象的时候。 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将是代理者的帮助子类的信息局部化的时候。

要点

1、工厂模式中,增加一种产品类,就要增加一个工厂类。

因为每个工厂类只能创建一种产品的实例。

2、工厂模式遵循开放-封闭原则。

工厂模式中,新增一种产品并不需要修改原有类,仅仅是扩展。

实例

还是以 简单工厂模式 里的例子来进行说明。

如何实现一个具有加减乘除基本功能的计算器? 

两种模式的 Product 和 ConcreteProduct 角色代码没有区别,不再赘述。

差异在于 Factory 角色部分,以及客户端部分,请在代码中体会。

Creator 角色

// Creator 角色,定义返回产品实例的公共工厂方法
 interface OperationFactory {
 public Operation FactoryMethod();
 }

ConcreteCreator 角色

和简单工厂模式相比,每一种产品都会有一个具体的工厂类负责生产实例。

// ConcreteCreator 角色,具体实现 Creator 中的方法
 class AddFactory implements OperationFactory {
     @Override
 public Operation FactoryMethod() {
 return new Add();
     }
 }
 
 // ConcreteCreator 角色,具体实现 Creator 中的方法
 class SubFactory implements OperationFactory {
     @Override
 public Operation FactoryMethod() {
 return new Sub();
     }
 }
 
 // ConcreteCreator 角色,具体实现 Creator 中的方法
 class MulFactory implements OperationFactory {
     @Override
 public Operation FactoryMethod() {
 return new Mul();
     }
 }
 
 // ConcreteCreator 角色,具体实现 Creator 中的方法
 class DivFactory implements OperationFactory {
     @Override
 public Operation FactoryMethod() {
 return new Div();
     }
 }

Client 角色

与简单工厂模式中无需关注具体创建不同,工厂模式中需要指定具体工厂,以负责生产具体对应的产品。

// Client 角色,需要指定具体工厂,以负责生产具体产品
 public class FactoryMethodPattern {
 public static void main(String[] args) {    
         OperationFactory factory = new SubFactory();
         Operation oper = factory.FactoryMethod();
         oper.numA = 3;
         oper.numB = 2;
 double result = oper.getResult();
         System.out.println("result = " + result);
     }
 }

C++版工厂方法模式

以下为一个C++版的工厂方法模式例子。

假设有两个台灯制造工厂,一个专门生产红色的灯,一个专门生产蓝色的灯。

在客户端里,我们实例化蓝灯工厂,来生产一个蓝灯。

#include "stdafx.h"
#include <string>
#include <iostream>
using namespace std;

//Product
class Light
{
public:
 virtual void TurnOn()  = 0;
 virtual void TurnOff() = 0;
};

class BlueLight : public Light
{
public:
 void TurnOn()
    {
        cout << "Turn on BlueLight." << endl;
    }

 void TurnOff()
    {
        cout << "Turn off BlueLight." << endl;
    }
};

class RedLight : public Light
{
public:
 void TurnOn()
    {
        cout << "Turn on RedLight." << endl;
    }

 void TurnOff()
    {
        cout << "Turn off RedLight." << endl;
    }
};

//Factory
class Factory
{
public:
 virtual Light* CreateLight() = 0;
};

class BlueLightFactory : public Factory
{
public:
    Light* CreateLight()
    {
 return new BlueLight;
    }
};

class RedLightFactory : public Factory
{
public:
    Light* CreateLight()
    {
 return new RedLight;
    }
};

int main()
{
    Factory *pBlueLightFactory = new BlueLightFactory;
    Light *pBlueLight = pBlueLightFactory->CreateLight();
 
    pBlueLight->TurnOn();
    pBlueLight->TurnOff();

 free(pBlueLight)
 free(pBlueLightFactory);
 
 return 0;
}

简单工厂模式 vs. 工厂方法模式

简单工厂模式相比于工厂方法模式

优点:工厂类中包含必要的逻辑判断,可根据客户端的选择条件动态实例化需要的类。对于客户端来说,去除了对具体产品的依赖。

缺点:违背了开放封闭原则。 每添加一个新的产品,都需要对原有类进行修改。增加维护成本,且不易于维护。

开发封闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

推荐阅读

本文属于 设计模式系列

简单工厂模式属于工厂模式家族,欢迎参考阅读 简单工厂模式抽象工厂方法模式

参考资料

《大话设计模式》 《HeadFirst设计模式》

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏编程

实现微信朋友圈所有动态点赞的自动化用例

本人在是呀UiAutomator的过程中,突发奇想,写一个自动给朋友圈点赞的用例,经过尝试,终于成功,效果不错。这个方法用的是for循环,也可以用while循环...

27110
来自专栏更流畅、简洁的软件开发方式

面向对象最重要的是“抽象”,三层最重要的也是“抽象”,没有抽象就不是真正的面向对象、三层。

  只用class的,那叫做“基于对象”,比如当初的vb6.0;只是分了三个项目,把以前写在一起的代码分成了三份,所谓的业务逻辑层就是一个传声筒,这一类自称三层...

2496
来自专栏Coco的专栏

BAT及各大互联网公司2014前端笔试面试题--Html,Css篇

1475
来自专栏YoungGy

ISLR_BootStrapping

起源 概述 置信区间 限制 比较 起源 有的时候,不只是想检定群体的mean,而是想检定群体的median。 这种情况下,CLT就不适用了,需要有新的方法策...

1719
来自专栏PHP实战技术

微信企业付款到个人钱包引发的坑之反思~!

企业付款到个人钱包也就是用户在微信公众平台提现可以直接打入提现者微信的钱包!但要满足: 1)企业开通微信支付90天 2)连续30天有交易才能开通此功能 ? 今...

3779
来自专栏微信终端开发团队的专栏

聊聊苹果的Bug - iOS 10 nano_free Crash

背景 iOS 10.0-10.1.1上,新出现了一类堆栈为nano_free字样的crash问题,困扰了我们一段时间,这里主要分享解决这个问题的思路,最后尝试...

4079
来自专栏前端新视界

如何使用 Bootstrap 搭建更合理的 HTML 结构

前言 Bootstrap 的成功不仅在于其简单易用,更在于其样式的规范性以及 HTML 结构的合理性。但是很多人在使用 Bootstrap 时只是依照文档盲目的...

2755
来自专栏前端侠2.0

css3的transform造成z-index无效, 附我的牛逼解法

我想锁表头及锁定列。昨天新找的方法是用css3的transform,这个应该在IE9以上都可以的。

723
来自专栏程序员宝库

使用思维导图,优雅的完成自己的代码

(点击上方 程序员宝库,可快速关注) 作者:九死蚕传人bo https://segmentfault.com/a/1190000012435669 我自己常常在...

29611
来自专栏搜云库

Java 10 新特性解密,引入类型推断机制,将于 2018 年 3 月 20 日发布

JDK 10 是 Java 10 标准版的部分实现,将于 2018 年 3 月 20 日发布,改进的关键点包括一个本地类型推断、一个垃圾回收的“干净”接口。

3888

扫码关注云+社区