示例代码来自《深入浅出设计模式》和《大话设计模式》

概述

简单工厂模式又被称为静态工厂模式,属于类的创建型模式。其实质是由一个工厂类根据传入的参量,动态决定应该创建出哪一个产品类的实例。

意图

专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

UML

图1 简单工厂模式的UML图

参与者

这个模式涉及的类或对象:

  • Creator

    • 它的角色就是工厂,负责生产各种产品。

  • Product

    • 它的角色是产品,是对所有产品的一个统称。在实现过程中,它是具体产品的公共基类。

  • ConcreteProduct

    • 它的角色是具体产品,它是每一种产品的具体实现。

来自《大话设计模式》的例子

这是一个很简单的计算器的例子,所有的计算工作被抽象成一个产品对象,而加或减这样一个具体计算被设计为一个具体产品。同时一个工厂类根据用户输入的不同返回具体的计算对象。

例子中涉及到的类与简单工厂模式中标准的类对应关系如下:

  • Product – Operation

  • ConcreteProduct – OperationAdd,OperationSub,OperationMul等

  • Creator – OperationFactory

using System;
 
// 运算类
public class Operation
{
    private double _numberA = 0;
    private double _numberB = 0;
 
    // 数字A
    public double NumberA
    {
        get
        {
            return _numberA;
        }
        set
        {
            _numberA = value;
        }
    }
 
    // 数字B
    public double NumberB
    {
        get
        {
            return _numberB;
        }
        set
        {
            _numberB = value;
        }
    }
 
    // 得到运算结果
    public virtual double GetResult()
    {
        double result = 0;
        return result;
    }
 
    // 检查输入的字符串是否准确
    public static string checkNumberInput(string currentNumber, string inputString)
    {
        string result = "";
        if (inputString == ".")
        {
            if (currentNumber.IndexOf(".") < 0)
            {
                if (currentNumber.Length == 0)
                    result = "0" + inputString;
                else
                    result = currentNumber + inputString;
            }
        }
        else if (currentNumber == "0")
        {
            result = inputString;
        }
        else
        {
            result = currentNumber + inputString;
        }
 
        return result;
    }
}
 
// 加法类
class OperationAdd : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA + NumberB;
        return result;
    }
}
 
// 减法类
class OperationSub : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA - NumberB;
        return result;
    }
}
 
// 乘法类
class OperationMul : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberA * NumberB;
        return result;
    }
}
 
// 除法类
class OperationDiv : Operation
{
    public override double GetResult()
    {
        double result = 0;
        if (NumberB == 0)
            throw new Exception("除数不能为0。");
        result = NumberA / NumberB;
        return result;
    }
}
 
// 平方类
class OperationSqr : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = NumberB * NumberB;
        return result;
    }
}
 
// 平方根类
class OperationSqrt : Operation
{
    public override double GetResult()
    {
        double result = 0;
        if (NumberB < 0)
            throw new Exception("负数不能开平方根。");
        result = Math.Sqrt(NumberB);
        return result;
    }
}
 
// 相反数类
class OperationReverse : Operation
{
    public override double GetResult()
    {
        double result = 0;
        result = -NumberB;
        return result;
    }
}
 
// 运算类工厂
public class OperationFactory
{
    public static Operation createOperate(string operate)
    {
        Operation oper = null;
        switch (operate)
        {
            case "+":
                {
                    oper = new OperationAdd();
                    break;
                }
            case "-":
                {
                    oper = new OperationSub();
                    break;
                }
            case "*":
                {
                    oper = new OperationMul();
                    break;
                }
            case "/":
                {
                    oper = new OperationDiv();
                    break;
                }
            case "sqr":
                {
                    oper = new OperationSqr();
                    break;
                }
            case "sqrt":
                {
                    oper = new OperationSqrt();
                    break;
                }
            case "+/-":
                {
                    oper = new OperationReverse();
                    break;
                }
        }
 
        return oper;
    }
}
 
class Program
{
    static void Main(string[] args)
    {
        try
        {
            Console.Write("请输入数字A:");
            string strNumberA = Console.ReadLine();
            Console.Write("请选择运算符号(+、-、*、/):");
            string strOperate = Console.ReadLine();
            Console.Write("请输入数字B:");
            string strNumberB = Console.ReadLine();
            string strResult = "";
 
            Operation oper;
            oper = OperationFactory.createOperate(strOperate);
            oper.NumberA = Convert.ToDouble(strNumberA);
            oper.NumberB = Convert.ToDouble(strNumberB);
            strResult = oper.GetResult().ToString();
 
            Console.WriteLine("结果是:" + strResult);
 
            Console.ReadLine();
        }
        catch (Exception ex)
        {
            Console.WriteLine("您的输入有错:" + ex.Message);
        }
    }
}

来自《深入浅出设计模式》的例子

这个例子中使用简单工厂实现了一个比萨店(我们还会用比萨店的例子来展示工厂方法模式和抽象工厂模式的应用),简单比萨工厂负责不同种类比萨的选择。首先我们给出这个示例的UML,然后是代码:

图2 使用比萨店例子的简单工厂UML图

using System;
using System.Text;
using System.Collections.Generic;
 
namespace DoFactory.HeadFirst.SimpleFactory.PizzaShop
{
    class PizzaTestDrive
    {
        static void Main(string[] args)
        {
            var factory = new SimplePizzaFactory();
            var store = new PizzaStore(factory);
 
            var pizza = store.OrderPizza("cheese");
            Console.WriteLine("We ordered a " + pizza.Name + "\n");
 
            pizza = store.OrderPizza("veggie");
            Console.WriteLine("We ordered a " + pizza.Name + "\n");
 
            // Wait for user
            Console.ReadKey();
        }
    }
    #region PizzaStore
 
    public class PizzaStore
    {
        private SimplePizzaFactory _factory;
 
        public PizzaStore(SimplePizzaFactory factory)
        {
            this._factory = factory;
        }
 
        public Pizza OrderPizza(string type)
        {
            Pizza pizza = _factory.CreatePizza(type);
 
            pizza.Prepare();
            pizza.Bake();
            pizza.Cut();
            pizza.Box();
 
            return pizza;
        }
    }
 
    #endregion
 
    #region SimplePizzaFactory
 
    public class SimplePizzaFactory
    {
        public Pizza CreatePizza(string type)
        {
            Pizza pizza = null;
            switch (type)
            {
                case "cheese": pizza = new CheesePizza(); break;
                case "pepperoni": pizza = new PepperoniPizza(); break;
                case "clam": pizza = new ClamPizza(); break;
                case "veggie": pizza = new VeggiePizza(); break;
            }
            Console.WriteLine(pizza);
            return pizza;
        }
    }
 
    #endregion
 
    #region Pizza
 
    abstract public class Pizza
    {
        private string _name;
        private string _dough;
        private string _sauce;
        private List<string> toppings = new List<string>();
 
        public Pizza(string name, string dough, string sauce)
        {
            this._name = name;
            this._dough = dough;
            this._sauce = sauce;
        }
 
        public string Name
        {
            get { return _name; }
            set { _name = value; }
        }
 
        public List<string> Toppings
        {
            get { return toppings; }
        }
 
        public void Prepare()
        {
            Console.WriteLine("Preparing " + _name);
        }
 
        public void Bake()
        {
            Console.WriteLine("Baking " + _name);
        }
 
        public void Cut()
        {
            Console.WriteLine("Cutting " + _name);
        }
 
        public void Box()
        {
            Console.WriteLine("Boxing " + _name);
        }
 
        // code to display pizza name and ingredients
        public override string ToString()
        {
            StringBuilder display = new StringBuilder();
            display.Append("---- " + _name + " ----\n");
            display.Append(_dough + "\n");
            display.Append(_sauce + "\n");
            foreach (string topping in toppings)
            {
                display.Append(topping + "\n");
            }
 
            return display.ToString();
        }
    }
 
    public class CheesePizza : Pizza
    {
        public CheesePizza() :
            base("Cheese Pizza", "Regular Crust", "Marinara Pizza Sauce")
        {
            Toppings.Add("Fresh Mozzarella");
            Toppings.Add("Parmesan");
        }
    }
 
    public class VeggiePizza : Pizza
    {
        public VeggiePizza() :
            base("Veggie Pizza", "Crust", "Marinara sauce")
        {
            Toppings.Add("Shredded mozzarella");
            Toppings.Add("Grated parmesan");
            Toppings.Add("Diced onion");
            Toppings.Add("Sliced mushrooms");
            Toppings.Add("Sliced red pepper");
            Toppings.Add("Sliced black olives");
        }
    }
 
    public class PepperoniPizza : Pizza
    {
        public PepperoniPizza() :
            base("Pepperoni Pizza", "Crust", "Marinara sauce")
        {
            Toppings.Add("Sliced Pepperoni");
            Toppings.Add("Sliced Onion");
            Toppings.Add("Grated parmesan cheese");
        }
    }
 
    public class ClamPizza : Pizza
    {
        public ClamPizza() :
            base("Clam Pizza", "Thin crust", "White garlic sauce")
        {
            Toppings.Add("Clams");
            Toppings.Add("Grated parmesan cheese");
        }
    }
    #endregion
}

实现要点和效果

简单工厂模式把变化集中到工厂中,每次新加一种品种,就要在工厂方法中做相应的修改。

简单工厂模式,每次要使用的时候,必需要知道事先约定好的,区别每个产品的标志符。

简单工厂模式的最大优点在于工厂类中包含了必要的逻辑判断,根据客户端的选择条件动态实例化相关的类,对于客户端来说,去除了与具体产品的依赖。

缺点

由于工厂类集中了所有实例的创建逻辑,很容易违反低耦合的设计原则。将全部创建逻辑都集中在了一起,使得逻辑变得十分复杂,而且当有新产品加入时,会进行大量代码的修改工作,对系统的扩展和维护也非常不利。这也正是与开放-封闭原则相对立的,所以为了更好的解耦合出现了工厂方法模式。

所有用简单工厂的地方,都可以考虑用发射技术来去除switch或if,解除分支判断带来的耦合。

总结

在简单工厂模式中。工厂类是整个模式的关键所在,它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。通过使用工厂类,外界可以从直接创建具体产品对象的尴尬局面中摆脱出来,仅仅需要负责"消费"对象就可以了,而不必管这些对象究竟是如何创建的具体细节,这样就明确区分了各自的职责和权力,有利于整个软件体系结构的优化。

学习设计模式第二十七 - GoF之外简单工厂模式的更多相关文章

  1. Java 设计模式系列(二)简单工厂模式和工厂方法模式

    Java 设计模式系列(二)简单工厂模式和工厂方法模式 实现了创建者和调用者的分离.分为:简单工厂模式.工厂方法模式.抽象工厂模式 简单工厂模式.工厂方法模式都很简单,就不详细介绍了. 一.简单工厂 ...

  2. [Python设计模式] 第1章 计算器——简单工厂模式

    github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...

  3. 设计模式(C#)——02简单工厂模式

    推荐阅读:  我的CSDN  我的博客园  QQ群:704621321       工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来.通俗来说,你只关心怎么用,不用关心怎么做 ...

  4. 【2016-10-17】【坚持学习】【Day8】【简单工厂模式】

    今天学习简单工厂模式, 结构 一个抽象产品 多个具体产品 一个工厂类,通过传入参数,new出不同的产品 代码: abstract class Product { //所有产品类的公共业务方法 publ ...

  5. Javascript设计模式理论与实战:简单工厂模式

    通常我们创建对象最常规的方法就是使用new关键字调用构造函数,这会导致对象之间的依赖性.工厂模式是一种有助于消除类之间依赖性的设计模式,它使用一个方法来决定要实例化哪一个类.本文详细介绍了简单工厂模式 ...

  6. 设计模式(Java语言)- 简单工厂模式

    简单工厂模式有称为静态工厂模式,属于设计模式中的创建型模式.简单工厂模式通过对外提供一个静态方法来统一为类创建实例.简单工厂模式的目的是实现类与类之间解耦,其次是客户端不需要知道这个对象是如何被穿创建 ...

  7. 设计模式(二)——Java简单工厂模式

    简单工厂模式 案例: 披萨的项目(要便于披萨种类的扩展,要便于维护) 1)披萨的种类很多(比如 GreekPizz.CheesePizz 等) 2)披萨的制作有 prepare,bake, cut, ...

  8. PYTHON设计模式,创建型之简单工厂模式

    这个系统,感觉思路清爽,,相信多练练,多思考,就会熟悉的.. http://www.jianshu.com/p/2450b785c329 #!/usr/bin/evn python #coding:u ...

  9. PHP设计模式(一):简单工厂模式

随机推荐

  1. PHP 开发API接口签名验证

    就安全来说,所有客户端和服务器端的通信内容应该都要通过加密通道(HTTPS)传输,明文的HTTP通道将会是man-in-the- middle及其各种变种攻击的温床.所谓man-in-the-midd ...

  2. python windows时间同步工具

    由于某种原因(BIOS电池没电),电脑的系统时间会与我们的北京时间不同步,将会导致如下问题: 1. 抢火车票的时候已经过时间了 2.别的同事都走了,你还以为没下班 …… 规避问题的方法:同步系统时间 ...

  3. 用python实现一个不排序的列表功能

    #!/usr/bin/env python # -*- coding: utf-8 -*- # learn <<Problem Solving with Algorithms and Da ...

  4. Chrome Extension 检查视图(无效)处理方法

    最近闲来无事,简单看了下Chrome扩展的开发,并且开发一个小小的翻译插件(TranslateBao)作为练手,开发细节不详述了,如果有新学习chrome extension开发的新人,可以参考源码, ...

  5. 【Cocos2d-x for WP8 学习整理】(5)文字显示全整理

    学习 Cocos2d-x 有一阵了,现在要做个小东西,第一步就遇到了文字展示的问题,于是想把可能遇到的问题统统整理一下.这一部分也不局限于wp8,全平台应该都是一个解决方案. 先在脑袋里大致想了一下, ...

  6. Sublime Text 3 快捷键

    选择类Ctrl+D 选中光标所占的文本,继续操作则会选中下一个相同的文本.Alt+F3 选中文本按下快捷键,即可一次性选择全部的相同文本进行同时编辑.举个栗子:快速选中并更改所有相同的变量名.函数名等 ...

  7. jq 剪切板

    文章链接 http://www.cnblogs.com/lkxsnow/p/5372665.html http://www.w3cfuns.com/notes/17735/020c2e68a60342 ...

  8. [转]Windows7文件夹转移清理臃肿的C盘

    当你使用Windows的时候,你会发现无论哪个版本的Windows,系统都会默认将用户文件夹和程序数据文件夹(xp下是Documents and Settings文件夹,而windows7和vista ...

  9. log4j使用--http://www.cnblogs.com/eflylab/archive/2007/01/11/618001.html

    package log4jTest.com; import java.io.FileReader; import org.apache.log4j.BasicConfigurator; import ...

  10. 跨界玩AR,迪奥、Hugo Boss等知名奢侈品牌将制造AR眼镜

    Snapchat因为阅后即焚消息应用而被人所熟知,前段时间这家公司拓展主要业务,未来将不再只有消息应用,还有款名为"Spectacles"的AR太阳镜.内置了一个摄像头,戴上之后即 ...