学习设计模式第二十七 - GoF之外简单工厂模式
示例代码来自《深入浅出设计模式》和《大话设计模式》
概述
简单工厂模式又被称为静态工厂模式,属于类的创建型模式。其实质是由一个工厂类根据传入的参量,动态决定应该创建出哪一个产品类的实例。
意图
专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
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之外简单工厂模式的更多相关文章
- Java 设计模式系列(二)简单工厂模式和工厂方法模式
Java 设计模式系列(二)简单工厂模式和工厂方法模式 实现了创建者和调用者的分离.分为:简单工厂模式.工厂方法模式.抽象工厂模式 简单工厂模式.工厂方法模式都很简单,就不详细介绍了. 一.简单工厂 ...
- [Python设计模式] 第1章 计算器——简单工厂模式
github地址:https://github.com/cheesezh/python_design_patterns 写在前面的话 """ 读书的时候上过<设计模 ...
- 设计模式(C#)——02简单工厂模式
推荐阅读: 我的CSDN 我的博客园 QQ群:704621321 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来.通俗来说,你只关心怎么用,不用关心怎么做 ...
- 【2016-10-17】【坚持学习】【Day8】【简单工厂模式】
今天学习简单工厂模式, 结构 一个抽象产品 多个具体产品 一个工厂类,通过传入参数,new出不同的产品 代码: abstract class Product { //所有产品类的公共业务方法 publ ...
- Javascript设计模式理论与实战:简单工厂模式
通常我们创建对象最常规的方法就是使用new关键字调用构造函数,这会导致对象之间的依赖性.工厂模式是一种有助于消除类之间依赖性的设计模式,它使用一个方法来决定要实例化哪一个类.本文详细介绍了简单工厂模式 ...
- 设计模式(Java语言)- 简单工厂模式
简单工厂模式有称为静态工厂模式,属于设计模式中的创建型模式.简单工厂模式通过对外提供一个静态方法来统一为类创建实例.简单工厂模式的目的是实现类与类之间解耦,其次是客户端不需要知道这个对象是如何被穿创建 ...
- 设计模式(二)——Java简单工厂模式
简单工厂模式 案例: 披萨的项目(要便于披萨种类的扩展,要便于维护) 1)披萨的种类很多(比如 GreekPizz.CheesePizz 等) 2)披萨的制作有 prepare,bake, cut, ...
- PYTHON设计模式,创建型之简单工厂模式
这个系统,感觉思路清爽,,相信多练练,多思考,就会熟悉的.. http://www.jianshu.com/p/2450b785c329 #!/usr/bin/evn python #coding:u ...
- PHP设计模式(一):简单工厂模式
随机推荐
- CA认证原理以及实现(上)
转自:http://yale.iteye.com/blog/1675344 原理基础数字证书为发布公钥提供了一种简便的途径,其数字证书则成为加密算法以及公钥的载体,依靠数字证书,我们可以构建一个简单的 ...
- Android学习资源整理
官方文档:https://developer.android.com/guide/index.html (万万没想到居然有中文) 网友整理的学习笔记,挺不错的 http://www.runoob.co ...
- 前端知识杂烩(Javascript篇)
1. JavaScript是一门什么样的语言,它有什么特点?2.JavaScript的数据类型都有什么?3.请描述一下 cookies,sessionStorage 和 localStorage 的区 ...
- HTML5 五子棋 - JS/Canvas 游戏
背景介绍 因为之前用c#的winform中的gdi+,java图形包做过五子棋,所以做这个逻辑思路也就驾轻就熟,然而最近想温故html5的canvas绘图功能(公司一般不用这些),所以做了个五子棋,当 ...
- mysql的查询、子查询及连接查询
>>>>>>>>>> 一.mysql查询的五种子句 where(条件查询).having(筛选).group by(分组). ...
- mysql优化笔记之分页
过年闲得蛋疼,于是看看mysql优化,看了网上好多关于分页的优化方法,但是呢,我亲自试上一把的时候,没有出现他们说的现象...难道是我的机器问题么? 下面看看我的实践记录,希望看到的加入进来交流一下O ...
- 关于 Lo、Hi、LoWord、HiWord
Cardinal 是 4 字节无符号的整型, 先看一个例数: Cardinal 例数: 4277991664 按字节划分: 第四字节 第三字节 第二字节 第一字节 二进制: 11111110 1111 ...
- 压力测试相关之ab命令
1. 短时压力测试工具 ab 命令(apache的工具) 关键指标: Requests per second: 98.52 [#/sec] (mean) ###平均每秒的请求数 Tim ...
- Codeforces663E Binary Table(FWT)
题目 Source http://codeforces.com/contest/663/problem/E Description You are given a table consisting o ...
- mac安装java8
http://stackoverflow.com/questions/24342886/how-to-install-java-8-on-mac brew tap caskroom/cask brew ...