C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】

简介: 原文:C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】一、引言       在上一篇文章中我们讲解了过渡的一种模式叫做【简单工厂】,也有叫【静态工厂】的,通过对简单工厂模式得了解,我们也发现了它的缺点,就是随着需求的变化我们要不停地修改工厂里面的方法的代码,需求变化越多,里面的If--Else--也越多,这样就会造成简单工厂的实现逻辑过于复杂。
原文: C#设计模式之二工厂方法模式(Factory Method Pattern)【创建型】

一、引言

       在上一篇文章中我们讲解了过渡的一种模式叫做【简单工厂】,也有叫【静态工厂】的,通过对简单工厂模式得了解,我们也发现了它的缺点,就是随着需求的变化我们要不停地修改工厂里面的方法的代码,需求变化越多,里面的If--Else--也越多,这样就会造成简单工厂的实现逻辑过于复杂。设计模式是遵循一定原则而得来的,比如,我们要怎么增加代码,怎么修改代码,不是想怎么来就怎么来的,其中一个原则就是OCP原则,中文是【开放关闭原则】,对增加代码开发,对修改代码关闭,所以我们就不能总是这样修改简单工厂里面的方法。本章介绍的工厂方法模式可以解决简单工厂模式中存在的这个问题,下面就具体看看工厂方法模式是如何解决该问题的。


二、工厂方法模式的胡介绍

      2.1、动机(Motivate)

           在软件系统的构建过程中,经常面临着“某个对象”的创建工作:由于需求的变化,这个对象(的具体实现)经常面临着剧烈的变化,但是它却拥有比较稳定的接口

      如何应对这种变化?如何提供一种“封装机制”来隔离出“这个易变对象”的变化,从而保持系统中“其他依赖对象的对象”不随着需求改变而改变?

      2.2、意图(Intent)

         
定义一个用于创建对象的接口,让子类决定实例化哪一个类。Factory Method使得一个类的实例化延迟到子类。                                        --《设计模式》GoF

      2.3、结构图(Structure)

          

     2.4、模式的组成

          可以看出,在工厂方法模式的结构图有以下角色:

          (1)、抽象工厂角色(Creator):
充当抽象工厂角色,定义工厂类所具有的基本的操作,任何具体工厂都必须继承该抽象类。

          (2)、具体工厂角色(ConcreteCreator):充当具体工厂角色,该类必须继承抽象工厂角色,实现抽象工厂定义的方法,用来创建具体产品。

          (3)、抽象产品角色(Product):充当抽象产品角色,定义了产品类型所有具有的基本操作,具体产品必须继承该抽象类。

          (4)、具体产品角色(ConcreteProduct):充当具体产品角色,实现抽象产品类对定义的抽象方法,由具体工厂类创建,它们之间有一一对应的关系。

     2.5、工厂方法模式的代码实现

         【简单工厂模式】的问题是:如果有新的需求就需要修改工厂类里面创建产品对象实例的那个方法的实现代码,在面向对象设计一个原则就是哪里有变化,我就封装哪里。还有另外两个大的原则,其一是:面向抽象编程,细节和高层实现都要依赖抽象,第二个原则是:多组合,少继承。这三个原则是最根本的原则,学习设计模式必须以这三个原则为基点,否则都是枉然。根据这三大原则又衍生出来6个具体的原则,分别是【单一职责原则】,【里氏替换原则】,【依赖倒置原则】,【接口隔离原则】、【迪米特法则】和【开闭原则,既然工厂类有变化,我们就封装它,面向抽象编程,我们先抽象出一个工厂基类,然后,每个需求就实现一个具体的工厂类,这样我们就符合了【开闭原则OCP】,让一个工厂生产一款产品,并一一对应。我们把具体产品的创建推迟到子类中,此时工厂类(这类是基类了)不再负责所有产品的创建,而只是给出具体工厂必须实现的接口,这样工厂方法模式就可以允许系统不修改工厂类逻辑的情况下来添加新产品,这样也就克服了简单工厂模式中缺点。下面就是工厂方法模式的实现代码:

 2 namespace 设计模式之工厂方法模式
 3 {
 4     /// <summary>
 5     /// 汽车抽象类
 6     /// </summary>
 7     public abstract class Car
 8     {
 9         // 开始行驶
10         public abstract void Go();
11     }
12 
13     /// <summary>
14     /// 红旗汽车
15     /// </summary>
16     public class HongQiCar : Car
17     {
18         public override void Go()
19         {
20             Console.WriteLine("红旗汽车开始行驶了");
21         }
22     }
23 
24     /// <summary>
25     /// 奥迪汽车
26     /// </summary>
27     public class AoDiCar : Car
28     {
29         public override void Go()
30         {
31             Console.WriteLine("奥迪汽车开始行驶了");
32         }
33     }
34 
35     /// <summary>
36     /// 抽象工厂类
37     /// </summary>
38     public abstract class Factory
39     {
40         // 工厂方法
41         public abstract Car CreateCar();
42     }
43 
44     /// <summary>
45     /// 红旗汽车工厂类
46     /// </summary>
47     public class HongQiCarFactory:Factory
48     {
49         /// <summary>
50         /// 负责生产红旗汽车
51         /// </summary>
52         /// <returns></returns>
53         public override Car CreateCar()
54         {
55             return new HongQiCar();
56         }
57     }
58 
59     /// <summary>
60     /// 奥迪汽车工厂类
61     /// </summary>
62     public class AoDiCarFactory:Factory
63     {
64         /// <summary>
65         /// 负责创建奥迪汽车
66         /// </summary>
67         /// <returns></returns>
68         public override Car CreateCar()
69         {
70             return new AoDiCar();
71         }
72     }
73 
74     /// <summary>
75     /// 客户端调用
76     /// </summary>
77     class Client
78     {
79         static void Main(string[] args)
80         {
81             // 初始化创建汽车的两个工厂
82             Factory hongQiCarFactory = new HongQiCarFactory();
83             Factory aoDiCarFactory = new AoDiCarFactory();
84 
85             // 生产一辆红旗汽车
86             Car hongQi = hongQiCarFactory.CreateCar();
87             hongQi.Go();
88 
89             //生产一辆奥迪汽车
90             Car aoDi = aoDiCarFactory.CreateCar();
91             aoDi.Go();
92 
93             Console.Read();
94         }
95     }  
96 }

    在【工厂方法模式】中,我们同样也把汽车的类抽象出来一个抽象的基类,这里正好符合了【面向抽象编程】,客户端在使用的时候不会依赖具体的什么汽车。使用工厂方法实现的系统,如果系统需要添加新产品时,我们可以利用多态性来完成系统的扩展,对于抽象工厂类和具体工厂中的代码都不需要做任何改动。例如,我们想增加一辆奔驰车,我们只需从Car抽象类下继承一个BenChiCar类,同时在从Factory抽象基类下继承一个“奔驰”的工厂类BenChinaCarFactory就可以了,这样扩展符合OCP的原则。具体代码为:

 1     /// <summary>
 2     /// 奔驰车
 3     /// </summary>
 4     public class BenChiCar : Car
 5     {
 6         /// <summary>
 7         /// 重写抽象类中的方法
 8         /// </summary>
 9         public override void Go()
10         {
11             Console.WriteLine("奔驰车开始行驶了!");
12         }
13     }
14 
15     /// <summary>
16     /// 奔驰车的工厂类
17     /// </summary>
18     public class BenChiCarFactory : Factory
19     {
20         /// <summary>
21         /// 负责生产奔驰车
22         /// </summary>
23         /// <returns></returns>
24         public override Car CreateCar()
25         {
26             return new BenChiCar();
27         }
28     }
29 
30     /// <summary>
31     /// 客户端调用
32     /// </summary>
33     class Client
34     {
35         static void Main(string[] args)
36         {
37 
38             // 如果客户又生产一辆奔驰车
39             // 再另外初始化一个奔驰车的工厂
40             Factory benChiCarFactory = new BenChiCarFactory();
41 
42             // 利用奔驰车的工厂生产奔驰车
43             Car benChi = benChiCarFactory.CreateCar();
44             benChi.Go();
45 
46             Console.Read();
47         }
48     }
49     


三、Factory Method模式的几个要点

  Factory Method模式主要用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。

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

      Factory Method模式解决“单个对象”的需求变化;

      AbstractFactory模式解决“系列对象”的需求变化;

      Builder模式解决“对象部分”的需求变化;

        3.1】、工厂方法模式的优点:

           (1)、 在工厂方法中,用户只需要知道所要产品的具体工厂,无须关系具体的创建过程,甚至不需要具体产品类的类名。

           (2)、在系统增加新的产品时,我们只需要添加一个具体产品类和对应的实现工厂,无需对原工厂进行任何修改,很好地符合了“开闭原则”。

        3.2】、工厂方法模式的缺点:

           (1)、每次增加一个产品时,都需要增加一个具体类和对象实现工厂,是的系统中类的个数成倍增加,在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。这并不是什么好事。

        3.3】、工厂方法模式使用的场景:

            (1)、一个类不知道它所需要的对象的类。在工厂方法模式中,我们不需要具体产品的类名,我们只需要知道创建它的具体工厂即可。

            (2)、一个类通过其子类来指定创建那个对象。在工厂方法模式中,对于抽象工厂类只需要提供一个创建产品的接口,而由其子类来确定具体要创建的对象,在程序运行时,子类对象将覆盖父类对象,从而使得系统更容易扩展。

            (3)、将创建对象的任务委托给多个工厂子类中的某一个,客户端在使用时可以无须关心是哪一个工厂子类创建产品子类,需要时再动态指定。


四、.NET中实现了工厂方法的类

.NET 类库中也有很多实现了工厂方法的类,例如Asp.net中,处理程序对象是具体用来处理请求,当我们请求一个*.aspx的文件时,此时会映射到System.Web.UI.PageHandlerFactory类上进行处理,而对*.ashx的请求将映射到System.Web.UI.SimpleHandlerFactory类中(这两个类都是继承于IHttpHandlerFactory接口的),关于这点说明我们可以在“C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\Web.Config”文件中找到相关定义,具体定义如下:

<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True"/>
 <add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True"/>
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True"/>

配置文件截图了一部分,有时间大家可以自己去研究一下。
下面我们就具体看下工厂方法模式在Asp.net中是如何实现的,如果对一个Index.aspx页面发出请求时,将会调用PageHandlerFactory中GetHandler方法来创建一个Index.aspx对象,它们之间的类图关系如下:



五、总结

       每种模式都有自己的使用场合,切记,如果使用错误,还不如不用。工厂方法模式通过面向对象编程中的多态性来将对象的创建延迟到具体工厂中,从而解决了简单工厂模式中存在的问题,也很好地符合了开放封闭原则(即对扩展开发,对修改封闭)。

学习设计模式我们一定要谨记设计模式的几大原则,否则是徒劳无功的。就像学务工一样,我们要记心法。6大原则就像孤独求败的独孤九剑的剑诀,学会了,变化无穷。

目录
相关文章
|
2月前
|
设计模式 安全 Java
C# 一分钟浅谈:设计模式之单例模式
【10月更文挑战第9天】单例模式是软件开发中最常用的设计模式之一,旨在确保一个类只有一个实例,并提供一个全局访问点。本文介绍了单例模式的基本概念、实现方式(包括饿汉式、懒汉式和使用 `Lazy&lt;T&gt;` 的方法)、常见问题(如多线程和序列化问题)及其解决方案,并通过代码示例详细说明了这些内容。希望本文能帮助你在实际开发中更好地应用单例模式,提高代码质量和可维护性。
60 1
|
2月前
|
设计模式 程序员 C#
C# 使用 WinForm MDI 模式管理多个子窗体程序的详细步骤
WinForm MDI 模式就像是有超能力一般,让多个子窗体井然有序地排列在一个主窗体之下,既美观又实用。不过,也要小心管理好子窗体们的生命周期哦,否则一不小心就会出现一些意想不到的小bug
196 0
|
3月前
|
设计模式 开发框架 前端开发
MVC 模式在 C# 中的应用
MVC(Model-View-Controller)模式是广泛应用于Web应用程序开发的设计模式,将应用分为模型(存储数据及逻辑)、视图(展示数据给用户)和控制器(处理用户输入并控制模型与视图交互)三部分,有助于管理复杂应用并提高代码可读性和维护性。在C#中,ASP.NET MVC框架常用于构建基于MVC模式的Web应用,通过定义模型、控制器和视图,实现结构清晰且易维护的应用程序。
63 2
|
3月前
|
设计模式 C# 开发者
C#设计模式入门实战教程
C#设计模式入门实战教程
|
4月前
|
前端开发 开发者 C#
深度解析 Uno Platform 中的 MVVM 模式:从理论到实践的全方位指南,助你轻松掌握通过 C# 与 XAML 构建高效可维护的跨平台应用秘籍
【8月更文挑战第31天】本文详细介绍如何在优秀的跨平台 UI 框架 Uno Platform 中实施 MVVM(Model-View-ViewModel)模式,通过一个简单的待办事项列表应用演示其实现过程。MVVM 模式有助于分离视图层与业务逻辑层,提升代码组织性、易测性和可维护性。Uno Platform 的数据绑定机制使视图与模型间的同步变得高效简便。文章通过构造 `TodoListViewModel` 类及其相关视图,展示了如何解耦视图与模型,实现动态数据绑定及命令处理,从而提高代码质量和开发效率。通过这一模式,开发者能更轻松地构建复杂的跨平台应用。
63 0
|
4月前
|
C#
WPF/C#:程序关闭的三种模式
WPF/C#:程序关闭的三种模式
97 0
|
1月前
|
设计模式 安全 Java
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
Kotlin教程笔记(51) - 改良设计模式 - 构建者模式
|
3月前
|
设计模式 数据库连接 PHP
PHP中的设计模式:提升代码的可维护性与扩展性在软件开发过程中,设计模式是开发者们经常用到的工具之一。它们提供了经过验证的解决方案,可以帮助我们解决常见的软件设计问题。本文将介绍PHP中常用的设计模式,以及如何利用这些模式来提高代码的可维护性和扩展性。我们将从基础的设计模式入手,逐步深入到更复杂的应用场景。通过实际案例分析,读者可以更好地理解如何在PHP开发中应用这些设计模式,从而写出更加高效、灵活和易于维护的代码。
本文探讨了PHP中常用的设计模式及其在实际项目中的应用。内容涵盖设计模式的基本概念、分类和具体使用场景,重点介绍了单例模式、工厂模式和观察者模式等常见模式。通过具体的代码示例,展示了如何在PHP项目中有效利用设计模式来提升代码的可维护性和扩展性。文章还讨论了设计模式的选择原则和注意事项,帮助开发者在不同情境下做出最佳决策。
|
1月前
|
设计模式 开发者 Python
Python编程中的设计模式:工厂方法模式###
本文深入浅出地探讨了Python编程中的一种重要设计模式——工厂方法模式。通过具体案例和代码示例,我们将了解工厂方法模式的定义、应用场景、实现步骤以及其优势与潜在缺点。无论你是Python新手还是有经验的开发者,都能从本文中获得关于如何在实际项目中有效应用工厂方法模式的启发。 ###
|
1月前
|
设计模式 安全 Java
Kotlin - 改良设计模式 - 构建者模式
Kotlin - 改良设计模式 - 构建者模式