由浅入深学“工厂模式”(1)

1 、学习工厂模式的预备知识:

首先声明这些预备知识并不是工厂模式仅仅需要,因为我先讲述工厂模式,所以在学习工厂模式之前将这些问题提出。

1.1 Upcasting

Upcasting中文翻译有好几个,比如向上类型转换、向上转型、上溯造型。我个人比较喜欢向上转型这个翻译,即简单又含义明确。向上转型这个概念,我在Bruce Eckel在的Thinking in c++Thinking in Java中都看到过,我不是很确定这个概念是否是他提出来的。向上转型是将把一个派生类当作它的基类使用。我们将一个更特殊的类型转换到一个更常规的类型,这当然是安全的。派生类是基类的一个超集。它可以包含比基类更多的方法,但它至少包含了基类的方法。向上转型给我们带来的好处就是我们可以将不同的派生通过一种统一的方式进行处理。向上转型带来的弊端就是我们向上转型的过程会丢失派生类的接口。既然有向上转型,也就有向下转型即DownCasting我们在此不做详细讨论。下面使用一个例子来示例向上转型。
     public class Base
     {
        public void Test()
        {
           MessageBox.Show("OK");
       }
    }
    public class Derive:Base
    {
     private void button1_Click(object sender, System.EventArgs e)
     {
         Base b=new Derive();
        b.Test();
     }

在有名的OOD的设计原则中有一个叫做里氏代换原则(Liskov Substitution Principle, LSP)。它的实质也就是讲向上转型。它的内容是:任何接收父类型的地方,都应当能够接收子类型,换句话说如果使用的是一个基类的话,那么一定适用于其子类,而且程序察觉不出基类对象和子类对象的区别。LSP是继承复用的基石,只有当派生类可以替换掉基类,软件的功能不受到影响时,基类才能真正被复用。
1.2 多态
我不敢想象离开了多态后的设计模式是一个什么样子。什么是多态,我喜欢总结这样一句话来回答这个问题,“一个接口,多种实现”。注意这里的接口不仅仅表示Interface关键字,是广义上的接口。在C#中实现接口我们有两种途径,一种是借助继承来实现,一种是借助Interface来实现。
2、工厂设计模式理论
2
.1 概述
工厂模式具体包括了简单工厂、工厂方法、抽象工厂,它们是按照从简单到复杂的顺序排列的,属于设计模式中的创建型,其中简单工厂并不属于GOF23中 模式。但是它是理解其它的工厂模式的一个很好的基础,所以很多人在讲述设计模式的时候会提到简单工厂模式。创建型模式关注的是对象的创建,创建型模式将创 建对象的过程进行了抽象,也可以理解为将创建对象的过程进行了封装,作为客户程序仅仅需要去使用对象,而不再关心创建对象过程中的逻辑。
2.2 不使用任何模式
我们现在有这样的一个设计,影像家电(VideoWiring)包括了DVDVCD。在基类VideoWiring中有PlayVideo方法,子类重载了这个方法。

我们如何来调用PlayVideo进行播放呢。我们可以看到下面的代码可以实现。

public abstract class VideoWiring
{
   
public abstract string PlayVideo();
}


public class VCD: VideoWiring
{
  
publicoverride string PlayVideo()
   {
     return"正在播放播放VCD";
    }

}

public class DVD: VideoWiring
{
  public override string PlayVideo()
   {
    
return"正在播放播放DVD";
   }

}

下面是调用对象的方法进行播放的代码:

private void PlayVideo()
{
    DVD dvd
=new DVD();
    MessageBox.Show(dvd.PlayVideo());
    VCD vcd
=new VCD();
     MessageBox.Show(VCD.PlayVideo());
}


上面的代码可以实现功能但是不好,为什么呢?类实现了多态,但是我们在调用的时候并没有利用多态。如果我们有很多的影像家电产品,就需要写很多的类似

dvd.PlayVideo();这样的语句。

下面是使用多态完成播放功能的代码:

private void PlayVideo()
{
    VideoWiring vw;
    vw
=new DVD();
    Play(vw);
    vw
=new VCD();
    Play(vw);
}

private void Play(VideoWiring vw)
 
{
   
string str=vw.PlayVideo();
    MessageBox.Show(str);
  }

我们再讨论一下,上面的代码存在的问题。虽然上的代码很短,应该不会有问题,但是我们定位的目标应该更高些,应该考虑怎样达到良好的封装效果,减少错误修改的机会。我们自然的应该考虑对象创建的问题了,能不能让不同的影像家电产品的创建方式相同,而且这个创建过程对使用者封装,也就是说让对象的创建象播放功能那样简单、统一。如果能够实现,会给我们的系统带来更大的可扩展性和尽量少的修改量。“哇!那该多好呀”。“不要羡慕了,来看看简单工厂模式,听说它能够实现”。 无论是什么影像家电产品,我们都可以使用一个统一的方式进行播放,即vw.PlayVideo()。

2.3 简单工厂模式
我们使用简单工厂对上面的代码继续改进,根据上面的分析我们考虑对对象创建进行近一步的封装。使用一个类专门来完成对对象创建的封装,这个类我们称为工厂,因为它的作用很单一就生成出一个个的类。下面是一个工厂类的示例代码:

public class Create
{
   
public static VideoWiring factory(string  VideoName)
   
{
        switch(VideoName)
       
{
           
case "DVD":
               
return new DVD();
            
case "VCD":
               
return new VCD();
        }

       
return null;
    }

  }


这样我们的客户端代码又可以更加有效简洁了:

private void PlayVideo()
{
    VideoWiring vw
=Create.factory("DVD");
    vw.PlayVideo();
    vw
=Create.factory("VCD");
    vw.PlayVideo();
}
注意:在上面的两段代码示例中我们就已经使用了向上转型。首先注意在 Create 类的 factory 方法中使用了 return new DVD(); 这样的语句,但是这个函数的返回值却是 VideoWiring,DVD 类的基类。所以我们的客户程序才可以使用 VideoWiring vw=Create.factory("DVD") 这样的语句。这样客户程序并不关心创建是如何完成的,以及创建的对象是什么,我们都可以调用基类统一的接口实现他们的功能。使用 UML 表示如下图所示:


我们将工厂模式推广到一般的情况,它的类图如下所示:


角色说明:

工厂类(Creator):根据业务逻辑创建具体产品,由客户程序直接调用。

抽象产品(Product):作为具体产品的基类,提供统一的接口,也是工厂类要返回的类型。

具体产品(Concrete Product):工厂类真正要创建的类型。上图中仅仅展示了一个具体产品,有多个产品的时候类似。

下面我们对简单工厂模式进行总结。使用简单工厂的好处是:

1、充分利用了多态性不管什么具体产品都返回抽象产品。2、充分利用了封装性,内部产品发生变化时外部使用者不会受到影响。他的缺点是:如果增加了新的产品,就必须得修改工厂(Factory)。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,创建多个产品族中的产品对象。这就是抽象工厂模式的用意。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值