详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录
园子里关于23种设计模式的博文已经可以说是成千上万、车载斗量、屯街塞巷、不计其数、数不胜数、摩肩接踵、汗牛充栋、车水马龙、门庭若市、琳琅满目直至让人眼花缭乱了。在这样的大环境下之所以来写设计模式类的博文,并不是像一些"非主流"的爱情观那样"宁缺毋滥"。 只是其一呢,因为相当于给自己做一个总结,加深一下自己这方面的认识,因为掌握了和把它写出来我感觉后者还可以对技能有一个提升,其二呢是因为最近公司有一个内部的training需要讲设计模式。

1.介绍:
2.延伸:
3.模拟场景:
欧美主导的以赛车为主题的系列电影《速度与激情》系列相信大家都看过,里面的男主角(zhǔ jué,加个拼音,经常听到有人说什么主脚主脚的,虽然之前我也不确定是zhǔ jué还是主脚,但是我没念过主脚,我在不确定的情况下我都是念男一号)范·迪塞尔在每一集里面做不同的事情都是开不同的车子,相信大家都觉得很酷吧。

人家酷也没办法,谁叫人家是大佬呢。这里我们试想一下,如果这是一套程序,我们该怎么设计?每次不同的画面或者剧情范·迪塞尔都需要按照导演的安排开不一样的车,去参加赛车需要开的是跑车,可能导演就会说下一场戏:范·迪塞尔下一场戏需要开跑车(参数),要去参加五环首届跑车拉力赛,这时候场务(工厂类)接到导演的命令(跑车参数)后需要从车库开出一辆跑车(具体产品)交到范·迪塞尔手上让他去准备五环首届跑车拉力赛。这套程序的整个生命周期就算完成了。(什么?没完成?难不成你还真想来个五环首届跑车拉力赛了啊:)
根据导演不同的指令,开的车是不一样的,但是车都是在车库中存在的。车都属于同一种抽象,车库里所有的车都有自己的特征,这些特征就是条件。导演发出指令的时候,只要告诉场务特征,场务就知道提什么车。这就简单工厂模式的典型案例。
4.简单工厂UML类图: (UML图是我用windows自带的paint手工画的,所以可能不是很专业)

5.代码演示:
抽象产品类代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 抽象产品类: 汽车
/// </summary>
public interface ICar
{
void GetCar();
}
}

具体产品类代码:

namespace CNBlogs.DesignPattern.Common
{
public enum CarType
{
SportCarType = 0,
JeepCarType = 1,
HatchbackCarType = 2
} /// <summary>
/// 具体产品类: 跑车
/// </summary>
public class SportCar : ICar
{
public void GetCar()
{
Console.WriteLine("场务把跑车交给范·迪塞尔");
}
} /// <summary>
/// 具体产品类: 越野车
/// </summary>
public class JeepCar : ICar
{
public void GetCar()
{
Console.WriteLine("场务把越野车交给范·迪塞尔");
}
} /// <summary>
/// 具体产品类: 两箱车
/// </summary>
public class HatchbackCar : ICar
{
public void GetCar()
{
Console.WriteLine("场务把两箱车交给范·迪塞尔");
}
}
}

简单工厂核心代码:

namespace CNBlogs.DesignPattern.Common
{
public class Factory
{
public ICar GetCar(CarType carType)
{
switch (carType)
{
case CarType.SportCarType:
return new SportCar();
case CarType.JeepCarType:
return new JeepCar();
case CarType.HatchbackCarType:
return new HatchbackCar();
default:
throw new Exception("爱上一匹野马,可我的家里没有草原. 你走吧!");
}
}
}
}

客户端调用代码:

//------------------------------------------------------------------------------
// <copyright file="Program.cs" company="CNBlogs Corporation">
// Copyright (C) 2015-2016 All Rights Reserved
// 原博文地址: http://www.cnblogs.com/toutou/
// 作 者: 请叫我头头哥
// </copyright>
//------------------------------------------------------------------------------
namespace CNBlogs.DesignPattern
{
using System;
using CNBlogs.DesignPattern.Common; class Program
{
static void Main(string[] args)
{
ICar car;
try
{
Factory factory = new Factory(); Console.WriteLine("范·迪塞尔下一场戏开跑车。");
car = factory.GetCar(CarType.SportCarType);
car.GetCar();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
}

简单工厂的简单案例就这么多,真正在项目实战的话可能还有需要改进和扩展的地方。因需求而定吧。
6.简单工厂的优点/缺点:
- 优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
- 缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则
1.介绍:
2.定义:
3.延伸:
4.模拟场景:
5.工厂方法UML类图: (UML图是我用windows自带的paint手工画的,所以可能不是很专业

6.代码演示:
抽象工厂代码:

namespace CNBlogs.DesignPattern.Common
{
public interface IFactory
{
ICar CreateCar();
}
}

抽象产品代码:

namespace CNBlogs.DesignPattern.Common
{
public interface ICar
{
void GetCar();
}
}

具体工厂代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 具体工厂类: 用于创建跑车类
/// </summary>
public class SportFactory : IFactory
{
public ICar CreateCar()
{
return new SportCar();
}
} /// <summary>
/// 具体工厂类: 用于创建越野车类
/// </summary>
public class JeepFactory : IFactory
{
public ICar CreateCar()
{
return new JeepCar();
}
} /// <summary>
/// 具体工厂类: 用于创建两厢车类
/// </summary>
public class HatchbackFactory : IFactory
{
public ICar CreateCar()
{
return new HatchbackCar();
}
}
}

具体产品代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 具体产品类: 跑车
/// </summary>
public class SportCar : ICar
{
public void GetCar()
{
Console.WriteLine("场务把跑车交给范·迪塞尔");
}
} /// <summary>
/// 具体产品类: 越野车
/// </summary>
public class JeepCar : ICar
{
public void GetCar()
{
Console.WriteLine("场务把越野车交给范·迪塞尔");
}
} /// <summary>
/// 具体产品类: 两箱车
/// </summary>
public class HatchbackCar : ICar
{
public void GetCar()
{
Console.WriteLine("场务把两箱车交给范·迪塞尔");
}
}
}

客户端代码:

//------------------------------------------------------------------------------
// <copyright file="Program.cs" company="CNBlogs Corporation">
// Copyright (C) 2015-2016 All Rights Reserved
// 原博文地址: http://www.cnblogs.com/toutou/
// 作 者: 请叫我头头哥
// </copyright>
//------------------------------------------------------------------------------
namespace CNBlogs.DesignPattern
{
using System.IO;
using System.Configuration;
using System.Reflection;
using CNBlogs.DesignPattern.Common; class Program
{
static void Main(string[] args)
{
// 工厂类的类名写在配置文件中可以方便以后修改
string factoryType = ConfigurationManager.AppSettings["FactoryType"]; // 这里把DLL配置在数据库是因为以后数据可能发生改变
// 比如说现在的数据是从sql server取的,以后需要从oracle取的话只需要添加一个访问oracle数据库的工程就行了
string dllName = ConfigurationManager.AppSettings["DllName"]; // 利用.NET提供的反射可以根据类名来创建它的实例,非常方便
var currentAssembly = System.Reflection.Assembly.GetExecutingAssembly();
string codeBase = currentAssembly.CodeBase.ToLower().Replace(currentAssembly.ManifestModule.Name.ToLower(), string.Empty);
IFactory factory = Assembly.LoadFrom(Path.Combine(codeBase, dllName)).CreateInstance(factoryType) as IFactory;
ICar car = factory.CreateCar();
car.GetCar();
}
}
}

7.工厂方法的优点/缺点:
- 优点:
- 子类提供挂钩。基类为工厂方法提供缺省实现,子类可以重写新的实现,也可以继承父类的实现。-- 加一层间接性,增加了灵活性
- 屏蔽产品类。产品类的实现如何变化,调用者都不需要关心,只需关心产品的接口,只要接口保持不变,系统中的上层模块就不会发生变化。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,其他的实现类都不需要关心,符合迪米特法则,符合依赖倒置原则,符合里氏替换原则。
- 多态性:客户代码可以做到与特定应用无关,适用于任何实体类。
- 缺点:需要Creator和相应的子类作为factory method的载体,如果应用模型确实需要creator和子类存在,则很好;否则的话,需要增加一个类层次。(不过说这个缺点好像有点吹毛求疵了)
1.介绍:
2.定义:
3.模拟场景:
4.场景分析:
上面的场景可能有点稀里糊涂的,但是用OO的思想结合前面的简单工厂和工厂方法的思路去理解的话,也好理解。
下面让我们来捋一捋这个思路:
- 抽象工厂:虚拟的车库,只是所有车库的一个概念。在程序中可能是一个借口或者抽象类,对其他车库的规范,开车和取包。
- 具体工厂:具体存在的车库,用来存放车和车对应的背包。在程序中继承抽象工厂,实现抽象工厂中的方法,可以有具体的产品。
- 抽象产品:虚拟的装备(车和对应的背包),也只是所有装备的一个概念。在程序中可能是多个接口或者多个抽象类,对具体的装备起到规范。
- 具体产品:活动参加的具体装备,它指的是组成装备的某一辆车或者背包。它继承自某一个抽象产品。
5.抽象工厂UML类图: (UML图是我用windows自带的paint手工画的,所以可能不是很专业)

6.代码演示:
抽象工厂代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 抽象工厂类
/// </summary>
public abstract class AbstractEquipment
{
/// <summary>
/// 抽象方法: 创建一辆车
/// </summary>
/// <returns></returns>
public abstract AbstractCar CreateCar(); /// <summary>
/// 抽象方法: 创建背包
/// </summary>
/// <returns></returns>
public abstract AbstractBackpack CreateBackpack();
}
}

抽象产品代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 抽象产品: 车抽象类
/// </summary>
public abstract class AbstractCar
{
/// <summary>
/// 车的类型属性
/// </summary>
public abstract string Type
{
get;
} /// <summary>
/// 车的颜色属性
/// </summary>
public abstract string Color
{
get;
}
} /// <summary>
/// 抽象产品: 背包抽象类
/// </summary>
public abstract class AbstractBackpack
{
/// <summary>
/// 包的类型属性
/// </summary>
public abstract string Type
{
get;
} /// <summary>
/// 包的颜色属性
/// </summary>
public abstract string Color
{
get;
}
}
}

具体工厂代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 运动装备
/// </summary>
public class SportEquipment : AbstractEquipment
{
public override AbstractCar CreateCar()
{
return new SportCar();
} public override AbstractBackpack CreateBackpack()
{
return new SportBackpack();
}
} /// <summary>
/// 越野装备 这里就不添加了,同运动装备一个原理,demo里只演示一个,实际项目中可以按需添加
/// </summary>
//public class JeepEquipment : AbstractEquipment
//{
// public override AbstractCar CreateCar()
// {
// return new JeeptCar();
// } // public override AbstractBackpack CreateBackpack()
// {
// return new JeepBackpack();
// }
//}
}

具体产品代码:

namespace CNBlogs.DesignPattern.Common
{
/// <summary>
/// 跑车
/// </summary>
public class SportCar : AbstractCar
{
private string type = "Sport";
private string color = "Red"; /// <summary>
/// 重写基类的Type属性
/// </summary>
public override string Type
{
get
{
return type;
}
} /// <summary>
/// 重写基类的Color属性
/// </summary>
public override string Color
{
get
{
return color;
}
}
} /// <summary>
/// 运动背包
/// </summary>
public class SportBackpack : AbstractBackpack
{
private string type = "Sport";
private string color = "Red"; /// <summary>
/// 重写基类的Type属性
/// </summary>
public override string Type
{
get
{
return type;
}
} /// <summary>
/// 重写基类的Color属性
/// </summary>
public override string Color
{
get
{
return color;
}
}
}
}
//具体产品可以有很多很多, 至于越野类的具体产品这里就不列出来了。

创建装备代码:

namespace CNBlogs.DesignPattern.Common
{
public class CreateEquipment
{
private AbstractCar fanCar;
private AbstractBackpack fanBackpack;
public CreateEquipment(AbstractEquipment equipment)
{
fanCar = equipment.CreateCar();
fanBackpack = equipment.CreateBackpack();
} public void ReadyEquipment()
{
Console.WriteLine(string.Format("老范背着{0}色{1}包开着{2}色{3}车。",
fanBackpack.Color,
fanBackpack.Type,
fanCar.Color,
fanCar.Type
));
}
}
}

客户端代码:

//------------------------------------------------------------------------------
// <copyright file="Program.cs" company="CNBlogs Corporation">
// Copyright (C) 2015-2016 All Rights Reserved
// 原博文地址: http://www.cnblogs.com/toutou/
// 作 者: 请叫我头头哥
// </copyright>
//------------------------------------------------------------------------------
namespace CNBlogs.DesignPattern
{
using System;
using System.Configuration;
using System.Reflection; using CNBlogs.DesignPattern.Common; class Program
{
static void Main(string[] args)
{
// ***具体app.config配置如下*** //
//<add key="assemblyName" value="CNBlogs.DesignPattern.Common"/>
//<add key="nameSpaceName" value="CNBlogs.DesignPattern.Common"/>
//<add key="typename" value="SportEquipment"/>
// 创建一个工厂类的实例
string assemblyName = ConfigurationManager.AppSettings["assemblyName"];
string fullTypeName = string.Concat(ConfigurationManager.AppSettings["nameSpaceName"], ".", ConfigurationManager.AppSettings["typename"]);
AbstractEquipment factory = (AbstractEquipment)Assembly.Load(assemblyName).CreateInstance(fullTypeName);
CreateEquipment equipment = new CreateEquipment(factory);
equipment.ReadyEquipment();
Console.Read();
}
}
}

抽象工厂模式符合了六大原则中的开闭原则、里氏代换原则、依赖倒转原则等等
7.抽象工厂的优点/缺点:
- 优点:
- 抽象工厂模式隔离了具体类的生产,使得客户并不需要知道什么被创建。
- 当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
- 增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
- 缺点:增加新的产品等级结构很复杂,需要修改抽象工厂和所有的具体工厂类,对“开闭原则”的支持呈现倾斜性。(不过说这个缺点好像有点吹毛求疵了)
这篇博文从晚上下班7点到家一直写到现在,说了一晚上的工厂,也扯了一晚上的速度与激情,在本博文完结的最后,给大家来一张速度与激情的画面精彩照。(ps:是不是觉得这种画面再配上一曲DJ一瓶啤酒会更嗨啊?哈哈...)
我们使用设计模式目的无非只有三个:a)缩短开发时间;b)降低维护成本;c)在应用程序之间和内部轻松集成。具体什么时候使用何种设计模式还得因项目而异。之所以对设计模式旧调重弹只是希望这个博文能对自己的架构之路有所提升,同时如果能帮助到其他人那就更完美了。
您可以考虑给头头来个小小的打赏以资鼓励,您的肯定将是我最大的动力。thx.
微信打赏
支付宝打赏
作 者:请叫我头头哥
出 处:http://www.cnblogs.com/toutou/
关于作者:专注于微软平台的项目开发。如有问题或建议,请多多赐教!
版权声明:本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。
特此声明:所有评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信我
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是作者坚持原创和持续写作的最大动力!
详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂) v阅读目录的更多相关文章
- 【经典案例】Python详解设计模式:策略模式
完成一项任务往往有多种方式,我们将其称之为策略. 比如,超市做活动,如果你的购物积分满1000,就可以按兑换现金抵用券10元,如果购买同一商品满10件,就可以打9折,如果如果购买的金额超过500,就可 ...
- Java设计模式之-----工厂模式(简单工厂,抽象工厂)
一.工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的. 工厂模式在<Java与模式>中分为三类:1)简单工厂模式(Simple Factor ...
- 设计模式(二 & 三)工厂模式:2-工厂方法模式
模拟场景: 沿用 设计模式(二)工厂模式:1-简单工厂模式 中关于运算器 Operation 的例子. 思想: 针对在 Easy Factory 中提出的,破坏“开-闭原则”的问题,Factory M ...
- java 抽象工厂模式简单实例
抽象工厂模式:提供一个创建一系列的相关的或者依赖的对象的接口,无需指定它们的具体实现类,具体的时间分别在子类工厂中产生. 类似于工厂模式:隔离了具体类的生产实现,使得替换具体的工厂实现类很容易.包含有 ...
- GOF提出的23种设计模式是哪些 设计模式有创建形、行为形、结构形三种类别 常用的Javascript中常用设计模式的其中17种 详解设计模式六大原则
20151218mark 延伸扩展: -设计模式在很多语言PHP.JAVA.C#.C++.JS等都有各自的使用,但原理是相同的,比如JS常用的Javascript设计模式 -详解设计模式六大原则 设计 ...
- 详解设计模式在Spring中的应用
设计模式作为工作学习中的枕边书,却时常处于勤说不用的尴尬境地,也不是我们时常忘记,只是一直没有记忆. 今天,在IT学习者网站就设计模式的内在价值做一番探讨,并以spring为例进行讲解,只有领略了其设 ...
- 详解设计模式在Spring中的应用---转载
Spring作为业界的经典框架,无论是在架构设计方面,还是在代码编写方面,都堪称行内典范.好了,话不多说,开始今天的内容. spring中常用的设计模式达到九种,我们一一举例: 第一种:简单工厂 又叫 ...
- 转:Windows下的PHP开发环境搭建——PHP线程安全与非线程安全、Apache版本选择,及详解五种运行模式。
原文来自于:http://www.ituring.com.cn/article/128439 Windows下的PHP开发环境搭建——PHP线程安全与非线程安全.Apache版本选择,及详解五种运行模 ...
- 举例详解Python中的split()函数的使用方法
这篇文章主要介绍了举例详解Python中的split()函数的使用方法,split()函数的使用是Python学习当中的基础知识,通常用于将字符串切片并转换为列表,需要的朋友可以参考下 函数:sp ...
随机推荐
- [pat]A1072 Gas Station
这道题的结点编号是字符串类型,处理的过程很有意思,用getID将house和GasStation进行区分 #include<bits/stdc++.h> using namespace s ...
- unity3d射线控制移动
看看效果图 代码: using UnityEngine; using System.Collections; public class T2 : MonoBehaviour { // Use this ...
- Bug 5323844-IMPDP无法导入远程数据库同义词的同义词
参见MOS文档: Bug 5323844 - SYNONYM for a SYNONYM in remote database not imported using IMPDP (文档 ID 5323 ...
- node.js连接本地数据库及json返回数据
新建一个文件夹node.js,目录下打开命令初始化一下 cnpm init 然后下载express框架 cnpm install express --save 接着下载数据库的依赖 cnpm inst ...
- 从0开始搭建vue+webpack脚手架(二)
接着从0开始搭建vue+webpack脚手架(一) 三.配置webpack-dev-server 1. webpack-dev-server自带一个node的服务器, 项目在服务端运行的同时可以实现热 ...
- 在liunx系统里面进行复制文件的时候报错:cp:omitting directiory
在复制的时候执行命令:cp /TEST/test1 /TEST/test2 结果报错:cp:omitting directior 报错原因:test1下面还有文件,不能删除 解决办法:cp -r / ...
- oauth2.0+app方式 webgis 授权
.认证方式有三种 Oauth2.0, Token-based http/windows 二.用户登录与应用登录区别 两者区别在于:当用户登录时,服务器端平台是否直接识别登录信息和验证登录信息. 应用登 ...
- java中的锁之AbstractQueuedSynchronizer源码分析(二)
一.成员变量. 1.目录. 2.state.该变量标记为volatile,说明该变量是对所有线程可见的.作用在于每个线程改变该值,都会马上让其他线程可见,在CAS(可见锁概念与锁优化)的时候是必不可少 ...
- web前端名词
HTML: HyperText Markup Language 超文本标记语言 XHTML:Extensible HyperText Markup Language 可扩展性超文本标记语 ...
- datetime处理日期和时间
datetime.now() # 获取当前datetimedatetime.utcnow() datetime(2017, 5, 23, 12, 20) # 用指定日期时间创建datetime 一.将 ...