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

概述

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

意图

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

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. 优化Linux内核参数

    转自:http://www.centoscn.com/CentOS/config/2013/0804/992.html vim /etc/sysctl.conf 1.net.ipv4.tcp_max_ ...

  2. 将一个实体数据保存到不同的数据表中<EntityFramework6.0>

    2014-11-22声明方式 public class Product { [Key] [DatabaseGenerated(DatabaseGeneratedOption.None)] public ...

  3. memcache的lru删除机制

    惰性删除,get时才删除 LRU原理:当某个单元被请求的时候,维护一个计数器,通过计数器来判断最近谁最少使用,那就把谁踢出去. 注:即使某个key设置的永久有效,也会被踢出来,这个就是永久数据被踢的现 ...

  4. JQuery表格插件DataTables 当前页合计功能

    公司项目表格插件使用的是DataTables,最近添加表合计功能,发现百度统一都是如图类型的代码,不知道是配置问题还是怎么了,在我的页面下根本不能用 var addd=0; $(document).r ...

  5. C#解析json文件的方法

    C# 解析 json JSON(全称为JavaScript Object Notation) 是一种轻量级的数据交换格式.它是基于JavaScript语法标准的一个子集. JSON采用完全独立于语言的 ...

  6. 【虚拟机】在VMware中安装Server2008之后配置网络连接的几种方式

    VMware虚拟机的网络连接方式分为三种:桥接模式.NAT模式.仅主机(Host Only) (1)桥接模式 桥接模式即在虚拟机中虚拟一块网卡,这样主机和虚拟机在一个网段中就被看作是两个独立的IP地址 ...

  7. XV Open Cup named after E.V. Pankratiev. GP of Tatarstan

    A. Survival Route 留坑. B. Dispersed parentheses $f[i][j][k]$表示长度为$i$,未匹配的左括号数为$j$,最多的未匹配左括号数为$k$的方案数. ...

  8. android studio 报错-----R全部显示红色 ---- .9图片报错

    导入android项目后,R全部变红,控制台有下面的提示 意思是缺少一些资源,比如说图片之类的,然后我发现确实少了一张图片资源,导入图片资源后,依旧报错,如下  Error:Execution fai ...

  9. 【ORACLE】ORA-12537 问题整理

    ORA-12537主要是ORALCE 监听问题,今天帮同事处理问题时,他问道一种情况,开始连接很正常,后续多次出现ORA-12537问题 简单整理了下 一般请况下 1-检查数据库服务器是否没有启动监听 ...

  10. MySQL表名和数据库关键字相同解决办法

    今天改他们的代码的时候,遇到了MySQL表名和数据库关键字的问题. 由于表名是关键字,导致增删改查都报错. Hibernate: select leave0_.id as id22_, leave0_ ...