细说设计模式之-让你看得懂的工厂模式系列

今天跟大家分享一下我对工厂系列模式的理解,主要包括简单工厂、工厂方法、抽象工厂模式。

场景一:
话说苹果和小米是两大手机巨头,他们各自推出的经典手机是IPhone手机系列和小米手机系列。
两家公司在手机的整个开发过程当中,都只负责产品的研发和设计工作,而手机制造则委托给手机工厂。

设计模式中有一个叫面向抽象编程的原则,在程序中体现为使用接口或者抽象类。下面我们将苹果和小米手机的共同特征和
行为来做一个抽象,这里我们使用抽象类,如下:

MobilePhone.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DPC.Domain
{
    public abstract class MobilePhone
    {
        public MobilePhone(string model,decimal price)
        {
            this.Model = model;
            this.Price = price;
        }

        /// <summary>
        /// 名字
        /// </summary>
        public abstract string Name { get; }

        /// <summary>
        /// 型号
        /// </summary>
        public string Model { get; private set; }

        /// <summary>
        /// 价格
        /// </summary>
        public decimal Price { get; private set; }

        /// <summary>
        /// 综合情况展示
        /// </summary>
        public virtual void Show()
        {
            Console.WriteLine("品牌:{0},型号:{1},价格:{2}", this.Name, this.Model, this.Price);
        }
    }
}

由于手机都有名字、型号、价格等等一些特征,所以我们可以将这些共有的行为和特征抽象到基类当中,避免子类中出现不必要的冗余代码。
接下来我们就用IPhone和XiaoMi手机两个类继承基类,在基类中实现各自独有的行为和特性,代码如下:

IPhone.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DPC.Domain
{
    public class IPhone : MobilePhone
    {
        private static readonly string name = "苹果";

        public IPhone(string model, decimal price)
            : base(model, price)
        { }

        public override string Name
        {
            get { return name; }
        }

        public override void Show()
        {
            Console.WriteLine("土豪手机闪亮登场......");
            Console.WriteLine("品牌:{0},型号:{1},价格:{2}",this.Name,this.Model,this.Price);
        }
    }
}

XiaoMi.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DPC.Domain
{
    public class XiaoMi : MobilePhone
    {
        public XiaoMi(string model, decimal price)
            : base(model, price)
        { }

        public override string Name
        {
            get { return "小米"; }
        }

        public override void Show()
        {
            Console.WriteLine("made in china手机闪亮登场......");
            Console.WriteLine("品牌:{0},型号:{1},价格:{2}", this.Name, this.Model, this.Price);
        }
    }
}

上面的代码中我们初步定义好了手机基类和实现类,并且用到了面向抽象编程的原则,为的是以后扩展程序更简单。
到现在为止,如果我们将上面的代码编译为DLL提供给第三方调用,那么调用的场景将会是这样子滴:

    MobilePhone phone = new IPhone("苹果", 5000);
    phone.Show();

    MobilePhone xiaomi = new XiaoMi("小米", 2000);
    xiaomi.Show();

调用者需要知道MobilePhone 这个类以及IPhone和XiaoMi两个子类,如果有别的品牌手机那么也需要知道相关子类。
如果当我们的手机品牌足够多,那么这个时候调用者调用我们的代码时将会无所适从。调用者不关心手机是如何生产的,
难道调用不能简化吗??

简化调用第一招,简单工厂(也称静态工厂)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DPC.Domain;

namespace DPC.CreateModel.SimpleFactory
{
    class Program
    {
        static void Main(string[] args)
        {
            MobilePhone phone = MobilePhoneFactory.GetMobilePhone("苹果",5000);
            phone.Show();
            Console.WriteLine();

            MobilePhone xiaomo = MobilePhoneFactory.GetMobilePhone("小米",2000);
            xiaomo.Show();
            Console.ReadKey();
        }
    }

    //简单工厂(又名静态工厂)
    public class MobilePhoneFactory
    {
        public static MobilePhone GetMobilePhone(string name,decimal price)
        {
            switch(name)
            {
                case "苹果":
                    return new IPhone("iphone6", price);
                case "小米":
                    return new XiaoMi("小米青春版", price);
                default:
                    throw new NotImplementedException("不存在的品牌");
            }
        }
    }
}

总结:这下不管有多少种不同的手机品牌,调用者只要告诉工厂需要的手机即可,根本不用去管具体是哪个手机子类被实例化了。
优点:该模式代码简单易于理解,学习成本较小。适用于场景单一、变动相对较小、对可扩展和可维护性要求不高的代码。
缺点:业务变动时需要修改工厂中的已有代码,违背了对修改关闭、对扩展开放的设计原则,不利于程序的扩展和维护。

场景二:
通过对简单工厂模式的使用,我们简化了外部调用代码的难度。但是,当我们增加一种产品时简单工厂里面的分支语句也得做相应的调整,
这显然违背了开闭的设计原则。针对简单工厂模式的这种缺陷,工厂方法模式提出了自己的解决方案。工厂方法
首先从单一职责原则入手,改进了简单工厂身兼数职的缺陷,一个具体的工厂方法只生产一种产品。其次从依赖倒置和面向抽象编程的原则入手,抽象
和提取出公共的工厂方法接口。

/// <summary>
    /// 手机工厂接口(只要实现了该接口的类就是具备生产某种手机能力的工厂,这里有可能是苹果手机或者小米手机工厂)
    /// </summary>
    public interface IMobilePhoneFactory
    {
        MobilePhone CreateMobilePhone();
    }

    //IPhone手机工厂
    public class IPhoneFactory : IMobilePhoneFactory
    {
        public MobilePhone CreateMobilePhone()
        {
            return new IPhone("iphone6 plus", 6500);
        }
    }

    //小米手机工厂
    public class XiaoMiFactory : IMobilePhoneFactory
    {
        public MobilePhone CreateMobilePhone()
        {
            return new XiaoMi("小米2代", 2500);
        }
    }

工厂方法调用代码:

class Program
    {
        static void Main(string[] args)
        {
            //创建生产小米手机的工厂
            IMobilePhoneFactory xiaomiFactory = new XiaoMiFactory();
            MobilePhone xiaomi = xiaomiFactory.CreateMobilePhone(); //调用工厂对象生产手机的方法
            xiaomi.Show();
            Console.WriteLine();

            //创建生产苹果手机的工厂
            IMobilePhoneFactory iphoneFactory = new IPhoneFactory();
            MobilePhone iphone = iphoneFactory.CreateMobilePhone(); //调用工厂对象生产手机的方法
            iphone.Show();

            //Console.WriteLine();
            //工厂方法与简单工厂结合使用
            //MobliePhoneFactoryHelper.GetPhone("苹果").Show();
            //MobliePhoneFactoryHelper.GetPhone("小米").Show();
            Console.ReadKey();
        }
    }

总结:工厂方法模式是对简单工厂模式的改造和升级,在工厂模式的基础上对简单工厂做了更高层次的抽象,抽象出工厂方法接口。
优点:工厂方法模式符合对修改关闭、对扩展开放的原则,具有更好的扩展性。
缺点:但工厂方法模式引入了更高的代码复杂度,学习和调用成本更高,且创建每个类的实例都需要相关的工厂类配合,所以某些情况下需要增加很多相关类。

备注:由于工厂方法在被外界调用时仍存在复杂度较高的问题,所以我们可以用简单工厂与工厂方法结合来解决(所以,没有万能的设计模式,关键是取长补短)。

#region 工厂方法与简单工厂结合
    public class MobliePhoneFactoryHelper
    {
        public static MobilePhone GetPhone(string name)
        {
            IMobilePhoneFactory factory = null;
            switch (name)
            {
                case "苹果":
                    factory = new IPhoneFactory();
                    return factory.CreateMobilePhone();
                case "小米":
                    factory = new XiaoMiFactory();
                    return factory.CreateMobilePhone();
                default:
                    throw new NotImplementedException("不存在的品牌");
            }
        }
    }
    #endregion

场景三:
工厂方法虽好,但在面对繁多的产品种类时也会有力不从心的时候。拿小米来说吧,产品系列包括手机、平板、盒子、路由器、电视。。。。,说不定以后还要生产
小米汽车之类的产品。如果我们现在要用工厂方法来实现小米的这种业务需求,那么则需要每个产品对应一个工厂,这样做的后果是资源浪费何其的严重啊。。。
所以,我们提出生产线的概念,一个工厂可以有多条生产线,每条生产线生产不同的产品。然后,我们的脑海中浮现出了这样的场景,某某苹果产品工厂里面有IPhone生产线、
IPad生产线、IMac生产线...。某某小米产品工厂里面有小米手机生产线、小米平板、小米电视生产线...。

以上说了这么多,就是为了诠释抽象工厂来做准备。抽象工厂是对工厂方法模式的改进升级,抽象工厂里面能同时生产多做不同的产品(也就是常说的产品族)。

/// <summary>
    /// 产品线工厂接口(可生产不同的产品,比如生产手机、平板、电视等等)
    /// </summary>
    public interface IProductLineFactory
    {
        /// <summary>
        /// 生产手机
        /// </summary>
        /// <returns></returns>
        MobilePhone CreateMobilePhone();

        /// <summary>
        /// 生产平板
        /// </summary>
        /// <returns></returns>
        Pad CreatePad();
    }

    public class AppleProductLineFactory : IProductLineFactory
    {

        public MobilePhone CreateMobilePhone()
        {
            return new IPhone("iphone5s", 5000);
        }

        public Pad CreatePad()
        {
            return new IPad("new ipad", 3000);
        }
    }

    public class XiaoMiProductLineFactory : IProductLineFactory
    {

        public MobilePhone CreateMobilePhone()
        {
            return new XiaoMi("小米2s", 2200);
        }

        public Pad CreatePad()
        {
            return new XiaoMiPad("小米平板", 1999);
        }
    }

调用代码:

class Program
    {
        static void Main(string[] args)
        {
            //小米生产线
            IProductLineFactory xiaomiProductLine = new XiaoMiProductLineFactory();
            xiaomiProductLine.CreateMobilePhone().Show(); //生产小米手机
            xiaomiProductLine.CreatePad().Show();//生产小米平板

            Console.WriteLine();

            IProductLineFactory appleProductLine = new AppleProductLineFactory();
            appleProductLine.CreateMobilePhone().Show(); //生产苹果手机
            appleProductLine.CreatePad().Show();//生产苹果平板

            Console.ReadKey();
        }

总结:抽象工厂创建的往往是一到多个不同类型的实例,而不是某一个类型的实例。它将对象创建的思想由点到面进行延伸,体现的是一种具体到抽象的思维过程,
所以由此而得名抽象工厂(非官方解释,个人理解而已)
优点:工厂方法模式虽符合了开闭原则,但每个类的对象需要一个对应的工厂,当我们需要创建多种不同类型对象时那么工厂方法类数量就会剧增。
所以,抽象工厂提出了产品族的概念,即相互关联的一类产品创建可以合并到一个实际工厂中的多个方法来创建,避免工厂类数量的爆炸。
缺点:当然,抽象工厂仍存在对客户端调用繁琐的问题,这里也可以和工厂方法一样来借助简单工厂简化调用,具体请参考工厂方法与简单工厂结合代码。

结语:工厂系列中的三大模式是紧密联系的,简单工厂->工厂方法->抽象工厂中的后一种设计模式都是对前一种模式缺陷的改造升级。

当然这里所说的缺陷也要辩证的来对待,在文中有提及,切不可一概而论。如果你觉得我的文章对你有点启迪,那么我的小伙伴不要吝啬给个赞吧。

猛击此处,获取代码。

时间: 2024-10-07 06:33:23

细说设计模式之-让你看得懂的工厂模式系列的相关文章

研磨设计模式解析及python代码实现——(一)简单工厂模式

最近在学设计模式,正巧书之前学了些python,但用的还不是很成熟.<研磨设计模式>书上只给了java代码,本着以练手为目标,我照着书上打了一遍java代码,在仔细体会其思想后,将其写成了python的代码.有不对的地方希望各位批评指正~ 具体原理不多做介绍,具体可以参考http://chjavach.iteye.com的博客,或者<研磨设计模式>的书. 一.背景介绍 接口思想: 众所周知,面向对象语言最大的特点便是封装,继承,多态这三个概念.而像Java等面向对象语言最核心的思想

设计模式(四):SIMPLE FACTORY简单工厂模式 -- 创建型模式

1.定义 简单工厂模式又称静态工厂方法模式.重命名上就可以看出这个模式一定很简单.它存在的目的很简单:定义一个用于创建对象的接口. 2.适用场景 如果一个客户要一款宝马车,一般的做法是客户去创建一款宝马车,然后拿来用.后来出现工业革命.用户不用去创建宝马车.因为客户有一个工厂来帮他创建宝马.想要什么车,这个工厂就可以建.比如想要320i系列车.工厂就创建这个系列的车.即工厂可以创建产品. 3.评价 优点: 工厂类是整个模式的关键.包含了必要的逻辑判断,根据外界给定的信息,决定究竟应该创建哪个具体

设计模式(一): abstract factory抽象工厂模式 -- 创建型模式

1.定义 为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类. 2.适用场景 1.一个系统要独立于它的产品创建.组合和表示. 2.一个系统要由多个产品系列中的一个来配置. 3.当你要强调一系列相关的产品对象的设计以便进行联合使用. 4.当你提供一个产品类库,而只想显示它们的接口而不是实现. 3.评价 1.它分离了具体的类 2.它使得易于交换产品系列 3.它有利于产品的一致性 4.难以支持新种类的产品 5."开放-封闭"原则要求系统对扩展开放,对修改封闭.通过扩展达到增

Android设计模式之一个例子让你彻底明白工厂模式(Factory Pattern)

提出疑问 这几天研究工厂模式的时候,看到网上的一些文章中举的例子我就很疑惑,我相信这也是许多人的疑惑:工厂模式的功能就是创建实例,我们创建实例直接new不就完了吗,干嘛还得再封装一层工厂类,然后用工厂类再去new出这个实例?这不多此一举吗? 比如我看到这样的例子,我们的用户分为金牌用户和银牌用户,我们要创建一个金牌用户或者银牌用户. 定义一个用户接口 public interface ICustomer { String describe(); } 金牌用户实现类 public class Go

【Javascript设计模式】第二课 神奇的魔术师——简单工厂模式

所谓简单工厂模式就是由一个方法来决定到底要创建那个类的实例,而这些实例经常都拥有相同的接口. 简单工厂模式主要运用一下几种情况(添加个人理解) 1.对象的构建有规律性,大部分相同只有个别不同,重复代码多 2.需要依赖具体环境创建不同的实例 3.处理大量具有相同属性的小对象 具体我们来看一个小例子: 大家在开发过程中经常遇到登陆模块,首先看以下的的具体的需求: 1.用户在输入框中输入的内容不符合规范,需要定义一个提示框提示:"您输入的内容不符合规范,请重新输入" 2.用户登陆提示用户不存

设计模式那点事读书笔记(2)----抽象工厂模式

抽象工厂模式: 此模式提供了一个接口,用于创建相关或者依赖对象的家族,而不需要指定具体实现类. 解决什么问题: 抽象工厂模式允许客户在使用抽象接口来创建一组相关的产品,客户类和工厂类分开,客户需要任何产品的时候,只需要向工厂请求即可,客户无须修改就可以获得新产品.从而实现客户从具体的产品中解耦. UML: 代码结构: 代码: 定义抽象产品: package com.demo.factory.model; /** * 抽象产品 */ public abstract class AbstractBa

痛定思痛后开始的设计模式(0)简单工厂模式

大三上学期结束了,所有科目的成绩都出了,拉稀的一塌糊涂,但我总觉得为时不晚,所以现在开始重新学习设计模式.Oracle.编译原理. 简单工厂模式 说实话其实很简单,就是当你实例化这个对象的时候,实例化的过程拿出来放到了工厂里面进行,你可以直接拿到这个对象但是你却看不到这个对象的实例过程和实例逻辑. 将你想要的对象名字或者对象特征传入工厂,工厂给你创建你要的对象. 下面是代码: 首先是基类: 1 public abstract class Car { 2 protected abstract vo

设计模式——介绍与工厂模式(扁平管理模式VS职业经理人模式)

本文主要对设计模式进行大概解说.特别是对工厂模式进行简明的解析: 一.设计模式的分类 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组合模式.享元模式. 行为型模式,共十一种:策略模式.模板方法模式.观察者模式.迭代子模式.责任链模式.命令模式.备忘录模式.状态模式.訪问者模式.中介者模式.解释器模式. 事实上还有两类:并发型模式和线程池模式. 二.设计模式的六大原则 1.开闭原则(Op

php设计模式(工厂模式)

/*//设计模式:程序进行设计用的,工厂模式 class YunSuan {  public $a;  public $b;  public $f;    function Jia()  {   return ($this->a+$this->b);   }   function Jian()  {   return ($this->a-$this->b);   }   function Cheng()  {   return ($this->a*$this->b);