二.工厂方法模式
Posted zaijianba
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二.工厂方法模式相关的知识,希望对你有一定的参考价值。
??工厂方法模式
引言:上一篇写的的是简单工厂模式,简单工厂模式只有三个要素(工厂、抽象产品、具体产品),它没有
工厂接口
,并且得到产品的方法一般是静态的,所以在工厂实现的扩展性上面较差,可以当作工厂模式的简化版。在简单工厂模式中,当增加一个产品子类的时候,还需要在工厂方法的Switch分支中新增一个判断,只做到了对扩展的开放,并没有做到对修改关闭,而这点在工厂方法模式中得到了一定的克服,作为简单工厂模式的升级版,工厂方法模式更适用于复杂一点的创建方法中。
1.何为工厂方法模式?
介绍
? 工厂方法模式(FACTORY METHOD)是一种常用的类创建型设计模式,此模式的核心精神是封装类中变化的部分,提取其中个性化善变的部分为独立类,通过依赖注入以达到解耦、复用和方便后期维护拓展的目的。它的核心结构有四个角色,分别是抽象工厂、具体工厂、抽象产品、具体产品 。
该模式中包含的角色及其职责:??
抽象工厂(Creator)角色:
是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
具体工厂(Concrete Creator)角色:
这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
抽象产品(Product)角色:
工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。
具体产品(Concrete Product)角色:
这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
可以看到,对比简单工厂模式,工厂方法模式多了个抽象工厂(Creator)的角色,这也是工厂方法模式的核心。
2.情景再现?
情景:
? 上一篇的例子中,我们使用了简单工厂模式根据系统的不同从而创建不同的系统实例,这一次我们使用工厂方法模式实现上一篇的需求。
上一篇的需求如下??
说起操作系统,市面上大概可以分为三种:
- Windows操作系统
- Linux操作系统
- Mac OS操作系统,
? 现在老板有个需求,根据用户使用的操作系统的不同,分别调用不同操作系统的 SayHello()
方法,和用户打招呼。
编写代码:
工厂方法模式代码:
工厂接口:任何在模式中创建的对象的工厂类必须实现这个接口
/// <summary>
/// 工厂抽象接口
/// </summary>
interface iosFactory
{
/// <summary>
/// 创建操作系统类
/// </summary>
/// <returns></returns>
OS CreateOS();
}
具体工厂:实现抽象工厂接口的具体工厂类
/// <summary>
/// Windows操作系统工厂
/// </summary>
class WindowsOSFactory : IOSFactory
{
public OS CreateOS()
{
return new WindowsOS();
}
}
/// <summary>
/// Mac操作系统工厂
/// </summary>
class MacOSFactory : IOSFactory
{
public OS CreateOS()
{
return new MacOS();
}
}
/// <summary>
/// Linux操作系统工厂
/// </summary>
class LinuxOSFactory : IOSFactory
{
public OS CreateOS()
{
return new LinuxOS();
}
}
抽象产品角色:工厂方法模式所创建的超类型,也就是产品对象的共同父类或者共同拥有的接口,在此例中为OS
类
//包含SayHello()方法
interface ISayHelloAble
{
string SayHello();
}
/// <summary>
/// 操作系统抽象父类
/// </summary>
public abstract class OS:ISayHelloAble
{
public abstract string SayHello();
}
具体产品角色:这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应,此例中为不同的操作系统。
/// <summary>
/// 具体的Windows操作系统,继承抽象的OS类
/// </summary>
class WindowsOS : OS
{
public override string SayHello()
{
string result = "你好,我是Windows操作系统,很高兴为您服务~";
return result;
}
}
/// <summary>
/// 具体的Linux操作系统
/// </summary>
class LinuxOS : OS
{
public override string SayHello()
{
string result = "你好,我是Linux操作系统,很高兴为您服务~";
return result;
}
}
/// <summary>
/// 具体的Mac操作系统
/// </summary>
class MacOS : OS
{
public override string SayHello()
{
string result = "你好,我是Mac OS操作系统,很高兴为您服务~";
return result;
}
}
客户端:
static void Main(string[] args)
{
//之后可以利用反射原理优化代码
IOSFactory oSFactory = new WindowsOSFactory();
OS concreteOS = oSFactory.CreateOS();
string greetings = concreteOS.SayHello();
Console.WriteLine(greetings);
Console.ReadKey();
}
结果:
? ?使用工厂方法模式之后,一个简单工厂模式的工厂类,变成了一个工厂抽象接口和多个具体生成对象的工厂,如果我们要对其它的操作系统进行支持,那么我们就不需要更改原有的工厂类了
? 例如我们需要增加Netware操作系统,我们只需要增加此功能的操作系统类和对应的工厂就行了。??
/// <summary>
/// 具体的Netware操作系统
/// </summary>
class NetwareOS : OS
{
public override string SayHello()
{
string result = "你好,我是Netware操作系统,很高兴为您服务~";
return result;
}
}
/// <summary>
/// Netware操作系统工厂
/// </summary>
class NetwareOSFactory : IOSFactory
{
public OS CreateOS()
{
return new NetwareOS();
}
}
?
但是仔细观察发现,工厂方法模式实现时,客户端需要决定实例化哪一个工厂来实现操作系统类,选择判断的问题还是存在的,也就是说,工厂方法把简单工厂的内部逻辑判断移到了客户端代码来进行,你想要增加功能,本来是改工厂类的,而现在是修改客户端!
? 那么有什么办法,让选择问题抛在客户端之外解决呢?我们可以使用“反射”。。
关于反射与工厂方法模式的结合将会在下一篇博客《抽象工厂模式》实现。
3.工厂方法模式"骨架"?
工厂方法模式UML图:
创建步骤:
步骤1: 创建抽象工厂类,定义具体工厂的公共接口;
步骤2: 创建抽象产品类 ,定义具体产品的公共接口;
步骤3: 创建具体产品类(继承抽象产品类) & 定义生产的具体产品;
步骤4:创建具体工厂类(继承抽象工厂类),定义创建对应具体产品实例的方法;
步骤5:外界通过调用具体工厂类的方法,从而创建不同具体产品类的实例
4.优缺点及使用场景??
优点
- 工厂方法克服了简单工厂违背开放-封闭原则的缺点,又保持了封装对象创建过程的优点,和简单工厂模式一样,他们都是集中封装了对象的创建,使得要更换对象时,不需要做大的改动就可实现,降低了客户端程序和产品对象的耦合。
- 工厂模式可以说是简单工厂模式的进一步抽象和拓展,在保留了简单工厂的封装优点的同时,让扩展变得简单,让继承变得可行,增加了多态性的体现。
缺点
- 添加新产品时,除了增加新产品类外,还要提供与之对应的具体工厂类,系统类的个数将成对增加,在一定程度上增加了系统的复杂度;同时,有更多的类需要编译和运行,会给系统带来一些额外的开销;
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
- 虽然保证了工厂方法内的对修改关闭,但对于使用工厂方法的类,如果要更换另外一种产品,仍然需要修改实例化的具体工厂类;
- 一个具体工厂只能创建一种具体产品
使用场景
工厂方法经常用在以下两种情况中:
- 第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
- 第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。
————————————————————————————————————————————
版权声明:本文为吴恺的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
为获得更好的阅读体验,推荐至我的个人博客阅读:https://www.wukailiving.cn/er-gong-han-fang-fa-mo-shi.html
原文链接:https://www.cnblogs.com/zaijianba/p/11519672.html
如有不足之处,欢迎指正!
以上是关于二.工厂方法模式的主要内容,如果未能解决你的问题,请参考以下文章