当前位置: 首页 > news >正文

步步为营 .NET 设计模式学习笔记 二十四、Factory Method(工厂方法模式)

概述

在软件系统中,经常面临着“某个对象”的创建工作,由于需求的变化,这个对象的具体实现经常面临着剧烈的变化,但是它却拥有比较稳定的接口。如何应对这种变化?提供一种封装机制来隔离出“这个易变对象”的变化,从而保持系统中“其它依赖该对象的对象”不随着需求的改变而改变?这就是要说的Factory Method模式了。

意图

定义一个用户创建对象的接口,让子类决定实例化哪一个类。Factory Method使一个类的实例化延迟到其子类。

结构图

PIC064.JPG

角色说明:

抽象工厂(Creator)角色:是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。

具体工厂(Concrete Creator)角色:这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。

抽象产品(Product)角色:工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。

具体产品(Concrete Product)角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。

生活中的例子

工厂方法定义一个用于创建对象的接口,但是让子类决定实例化哪个类。压注成型演示了这种模式。塑料玩具制造商加工塑料粉,将塑料注入到希望形状的模具中。玩具的类别(车,人物等等)是由模具决定的。

PIC069.jpg

 

示例用例图

如果去麦当劳吃汉堡,汉堡的制作过程就是一个工厂方法模式,用例图如下:

image

 

代码设计

先创建Hamburger.cs:

    public abstract class Hamburger
    {
        public abstract string BuyHamburger();
    }

 

再创建CheeseBurger.cs:

    public class CheeseBurger : Hamburger
    {
        public override string BuyHamburger()
        {
            return "你要的是起司汉堡\n";
        }
    }

 

再创建RoastedChickenBurger.cs:

    public class RoastedChickenBurger : Hamburger
    {
        public override string BuyHamburger()
        {
            return "你要的是黄金烤鸡腿堡\n";
        }
    }

 

再创建ConcreteHamburger.cs:

    public class ConcreteHamburger
    {
        public static string ProduceHamburger(string category)
        {
            Assembly assembly = Assembly.Load("Factory");
            Hamburger hamburger = assembly.CreateInstance("Factory." + category) as Hamburger;
            return hamburger.BuyHamburger();
        }
    }

 

最后再调用:

    public partial class Run : Form
    {
        public Run()
        {
            InitializeComponent();
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            //-------------------------------------
            rtbResult.AppendText(ConcreteHamburger.ProduceHamburger("CheeseBurger"));
            rtbResult.AppendText(ConcreteHamburger.ProduceHamburger("RoastedChickenBurger"));

        }

    }

 

运行结果如下图:

image

实现要点

1.Factory Method模式的两种情况:一是Creator类是一个抽象类且它不提供它所声明的工厂方法的实现;二是Creator是一个具体的类且它提供一个工厂方法的缺省实现。

2.工厂方法是可以带参数的。

3.工厂的作用并不仅仅只是创建一个对象,它还可以做对象的初始化,参数的设置等。

4.通过继承创建具体产品。很多时候,每一种具体产品对应一个具体的工厂来创建。

5.使用具体工厂类来决定怎么样创建具体产品。调用方并不关心工厂创建的是哪个制作场景,它只用知道工厂给我的是一个产品名称即可。

效果

1.用工厂方法在一个类的内部创建对象通常比直接创建对象更灵活。

2.Factory Method模式通过面向对象的手法,将所要创建的具体对象的创建工作延迟到了子类,从而提供了一种扩展的策略,较好的解决了这种紧耦合的关系。

适用性

在以下情况下,适用于工厂方法模式:

1. 当一个类不知道它所必须创建的对象的类的时候。

2. 当一个类希望由它的子类来指定它所创建的对象的时候。

3. 当类将创建对象的职责委托给多个帮助子类中的某一个,并且你希望将哪一个帮助子类是代理者这一信息局部化的时候。

4.从代码角度来说, 如果我们需要创建一个易变的对象,或是希望对象由子类决定创建哪个对象的时候可以考虑工厂方法。

5.从应用角度来说, 如果我们觉得具体产品的创建不稳定,或者客户端根本无需知道创建哪个具体产品的时候可以使用工厂方法。后者对于框架和工具包软件来说更常见,比如有一个打印类负责打印图纸,我们需要得到一个打印对象,对于调用方来说并不知道要使用超宽打印对象还是普通打印对象,我们可以通过工厂方法使客户端和抽象打印工厂直接沟通,由它来决定具体创建哪个打印对象。

总结

Factory Method模式是设计模式中应用最为广泛的模式,通过本文,相信读者已经对它有了一定的认识。然而我们要明确的是:在面向对象的编程中,对象的创建工作非常简单,对象的创建时机却很重要。Factory Method要解决的就是对象的创建时机问题,它提供了一种扩展的策略,很好地符合了开放封闭原则。

转载于:https://www.cnblogs.com/springyangwc/archive/2011/05/05/2038342.html

相关文章:

  • 杉杉股份聘方正科技前副总任伟泉掌帅印
  • npm安装任何包报错,解决方法:
  • Windows 7快速定位照片方法
  • Calendar类,运用Calendar类打印日历
  • 禁止浏览器自动保存密码弹框
  • tomcat:javax.servlet.http.HttpServletRequest cannot be resolved
  • Git忽略规则及.gitignore规则不生效的解决办法
  • 手把手教你实现微信聊天框随文本升高
  • packge-info.java
  • Java 线程 — ThreadLocal
  • 前端学数据库之数据表操作
  • [转]C#中捕捉对话框的文本内容 EnumChildWindows
  • (转)LINQ之路
  • 创建dialog
  • SQL Scripts Template Files Path
  • SegmentFault for Android 3.0 发布
  • [笔记] php常见简单功能及函数
  • 【comparator, comparable】小总结
  • 0x05 Python数据分析,Anaconda八斩刀
  • axios请求、和返回数据拦截,统一请求报错提示_012
  • iOS编译提示和导航提示
  • JavaScript类型识别
  • js中forEach回调同异步问题
  • Kibana配置logstash,报表一体化
  • Linux中的硬链接与软链接
  • nginx 负载服务器优化
  • Transformer-XL: Unleashing the Potential of Attention Models
  • vue-router的history模式发布配置
  • 和 || 运算
  • 目录与文件属性:编写ls
  • 学习ES6 变量的解构赋值
  • 一起来学SpringBoot | 第三篇:SpringBoot日志配置
  • 3月7日云栖精选夜读 | RSA 2019安全大会:企业资产管理成行业新风向标,云上安全占绝对优势 ...
  • LevelDB 入门 —— 全面了解 LevelDB 的功能特性
  • 蚂蚁金服CTO程立:真正的技术革命才刚刚开始
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​决定德拉瓦州地区版图的关键历史事件
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • #git 撤消对文件的更改
  • #绘制圆心_R语言——绘制一个诚意满满的圆 祝你2021圆圆满满
  • (七)理解angular中的module和injector,即依赖注入
  • (一)appium-desktop定位元素原理
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • (转)setTimeout 和 setInterval 的区别
  • .bashrc在哪里,alias妙用
  • .bat批处理(一):@echo off
  • .NET Core SkiaSharp 替代 System.Drawing.Common 的一些用法
  • .NET Core 中插件式开发实现
  • .NET 编写一个可以异步等待循环中任何一个部分的 Awaiter
  • .NET 读取 JSON格式的数据
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .NET精简框架的“无法找到资源程序集”异常释疑
  • .NET开源全面方便的第三方登录组件集合 - MrHuo.OAuth
  • .Net下C#针对Excel开发控件汇总(ClosedXML,EPPlus,NPOI)