详解设计模式之工厂模式(简单工厂+工厂方法+抽象工厂)

园子里关于23种设计模式的博文已经能够说是成千上万、车载斗量、屯街塞巷、不可胜数、数不胜数、摩肩接踵、汗牛充栋、车水马龙、门庭若市、琳琅满目直至让人眼花缭乱了。在这样的大环境下之因此来写设计模式类的博文,并非像一些"非主流"的爱情观那样"宁缺毋滥"。 只是其一呢,由于至关于给本身作一个总结,加深一下本身这方面的认识,由于掌握了和把它写出来我感受后者还能够对技能有一个提高,其二呢是由于最近公司有一个内部的training须要讲设计模式。html

C# 设计模式
v写在前面
在这里呢,须要向园子里全部写过设计模式的前辈们和程杰老师致敬,在coding的道路上从当初刚毕业的懵懵懂懂到如今的XXXXX,一路上是大家给了咱们coding启迪。不矫情了,开始正事。(建议在正式认识设计模式以前,能够先参照个人 上一篇博文学习一下设计模式的六大原则。)
v简单工厂模式

1.介绍: sql

简单工厂模式是属于建立型模式,又叫作静态工厂方法(Static Factory Method)模式,但不属于23种GOF设计模式之一。简单工厂模式是由一个工厂对象决定建立出哪种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式,能够理解为是不一样工厂模式的一个特殊实现。

2.延伸: 数据库

试想一下,当咱们在coding的时候,在A类里面只要NEW了一个B类的对象,那么A类就会从某种程度上依赖B类。若是在后期需求发生变化或者是维护的时候,须要修改B类的时候,咱们就须要打开源代码修改全部与这个类有关的类了,作太重构的朋友都知道,这样的事情虽然没法彻底避免,但确实是一件让人心碎的事情。

3.模拟场景: windows

欧美主导的以赛车为主题的系列电影《速度与激情》系列相信你们都看过,里面的男主角(zhǔ jué,加个拼音,常常听到有人说什么主脚主脚的,虽然以前我也不肯定是zhǔ jué仍是主脚,可是我没念过主脚,我在不肯定的状况下我都是念男一号)范·迪塞尔在每一集里面作不一样的事情都是开不一样的车子,相信你们都以为很酷吧。设计模式

C# 抽象工厂设计模式

人家酷也没办法,谁叫人家是大佬呢。这里咱们试想一下,若是这是一套程序,咱们该怎么设计?每次不一样的画面或者剧情范·迪塞尔都须要按照导演的安排开不同的车,去参加赛车须要开的是跑车,可能导演就会说下一场戏:范·迪塞尔下一场戏须要开跑车(参数),要去参加五环首届跑车拉力赛,这时候场务(工厂类)接到导演的命令(跑车参数)后须要从车库开出一辆跑车(具体产品)交到范·迪塞尔手上让他去准备五环首届跑车拉力赛。这套程序的整个生命周期就算完成了。(什么?没完成?难不成你还真想来个五环首届跑车拉力赛了啊:)架构

根据导演不一样的指令,开的车是不同的,可是车都是在车库中存在的。车都属于同一种抽象,车库里全部的车都有本身的特征,这些特征就是条件。导演发出指令的时候,只要告诉场务特征,场务就知道提什么车。这就简单工厂模式的典型案例。oracle

4.简单工厂UML类图: (UML图是我用windows自带的paint手工画的,因此可能不是很专业)app

C# 简单工厂模式

5.代码演示: 框架

抽象产品类代码: ide

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的高内聚的责任分配原则
v工厂方法模式

1.介绍: 

工厂方法模式Factory Method,又称多态性工厂模式。在工厂方法模式中,核心的工厂类再也不负责全部的产品的建立,而是将具体建立的工做交给子类去作。该核心类成为一个抽象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪个产品类应当被实例化这种细节。

2.定义: 

工厂方法模式是简单工厂模式的衍生,解决了许多简单工厂模式的问题。首先彻底实现‘开-闭 原则’,实现了可扩展。其次更复杂的层次结构,能够应用于产品结果复杂的场合。

3.延伸: 

在上面简单工厂的引入中,咱们将实例化具体对象的工做所有交给了专门负责建立对象的工厂类(场务)中,这样就能够在咱们获得导演的命令后建立对应的车(产品)类了。可是剧组的导演是性情比较古怪的,可能指令也是无限变化的。这样就有了新的问题,一旦导演发出的指令时咱们没有预料到的,就必须得修改源代码。这也不是很合理的。工厂方法就是为了解决这类问题的。

4.模拟场景: 

仍是上面范·迪塞尔要去参加五环首届跑车拉力赛的场景。由于要拍摄《速度与激情8》,导演组车的种类增多了,阵容也更加豪华了,加上导演古怪的性格可能每一场戏绝对须要试驾几十种车。若是车库没有的车(具体产品类)能够由场务(具体工厂类)直接去4S店取,这样没增长一种车(具体产品类)就要对应的有一个场务(具体工厂类),他们互相之间有着各自的职责,互不影响,这样可扩展性就变强了。

5.工厂方法UML类图: (UML图是我用windows自带的paint手工画的,因此可能不是很专业

C# 工厂方法模式

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和子类存在,则很好;不然的话,须要增长一个类层次。(不过说这个缺点好像有点吹毛求疵了)
v抽象工厂模式

1.介绍: 

抽象工厂模式是全部形态的工厂模式中最为抽象和最具通常性的一种形态。抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。抽象工厂模式能够向客户端提供一个接口,使客户端在没必要指定产品的具体的状况下,建立多个产品族中的产品对象。根据里氏替换原则,任何接受父类型的地方,都应当可以接受子类型。所以,实际上系统所须要的,仅仅是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。换言之,也就是这些抽象产品的具体子类的实例。工厂类负责建立抽象产品的具体子类的实例。

2.定义: 

为建立一组相关或相互依赖的对象提供一个接口,并且无需指定他们的具体类。

3.模拟场景: 

咱们仍是继续范·迪塞尔的例子,每每这些大牌生活中常常参加一些活动,或是商务活动或是公益活动。无论参加什么活动,加上老范(范·迪塞尔名字太长,如下文中简称老范)的知名度,他的车确定很多,可能光跑车或者光越野车就有多辆。好比说有跑车(多辆,跑车系列的具体产品)、越野车(多辆,越野车系列的具体产品)、两箱车(多辆,两箱车系列的具体产品)。可能不少大牌明星都是如此的。假设老范家里,某一个车库(具体工厂)只存放某一系列的车(好比说跑车车库只存放跑车一系列具体的产品),每次要某一辆跑车的时候确定要从这个跑车车库里开出来。用了OO(Object Oriented,面向对象)的思想去理解,全部的车库(具体工厂)都是车库类(抽象工厂)的某一个,而每一辆车又包括具体的开车时候所背的包(某一具体产品。包是也是放在车库里的,不一样的车搭配不一样的包,咱们把车和车对应的背包称做出去参加活动的装备),这些具体的包其实也都是背包(抽象产品),具体的车其实也都是车(另外一个抽象产品)。

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.抽象工厂的优势/缺点: 

  • 优势:
    • 抽象工厂模式隔离了具体类的生产,使得客户并不须要知道什么被建立。
    • 当一个产品族中的多个对象被设计成一块儿工做时,它能保证客户端始终只使用同一个产品族中的对象。
    • 增长新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
  • 缺点:增长新的产品等级结构很复杂,须要修改抽象工厂和全部的具体工厂类,对“开闭原则”的支持呈现倾斜性。(不过说这个缺点好像有点吹毛求疵了)
v博客总结

这篇博文从晚上下班7点到家一直写到如今,说了一夜的工厂,也扯了一夜的速度与激情,在本博文完结的最后,给你们来一张速度与激情的画面精彩照。(ps:是否是以为这种画面再配上一曲DJ一瓶啤酒会更嗨啊?哈哈...)

咱们使用设计模式目的无非只有三个:a)缩短开发时间;b)下降维护成本;c)在应用程序之间和内部轻松集成。具体何时使用何种设计模式还得因项目而异。之因此对设计模式旧调重弹只是但愿这个博文能对本身的架构之路有所提高,同时若是能帮助到其余人那就更完美了。

 


做  者:请叫我头头哥
出  处:http://www.cnblogs.com/toutou/
关于做者:专一于基础平台的项目开发。若有问题或建议,请多多赐教!
版权声明:本文版权归做者和博客园共有,欢迎转载,但未经做者赞成必须保留此段声明,且在文章页面明显位置给出原文连接。
特此声明:全部评论和私信都会在第一时间回复。也欢迎园子的大大们指正错误,共同进步。或者直接私信
声援博主:若是您以为文章对您有帮助,能够点击文章右下角推荐一下。您的鼓励是做者坚持原创和持续写做的最大动力!

相关文章
相关标签/搜索