《.NET程序员面试秘笈》---- 面试题11 举例说明简单工厂模式的作用

本节书摘来自异步社区《.NET程序员面试秘笈》一书中的第1章,面试题11,作者: 张云翯, 更多章节内容可以访问云栖社区“异步社区”公众号查看。

面试题11 举例说明简单工厂模式的作用

.NET程序员面试秘笈
【考点】工厂模式的理解,工厂模式在实际应用中的编写。

【出现频率】

【解答】

在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。为了绕过常规对象的创建方法(new运算符创建实例),工厂模式提供一种“封装机制”来减少使用程序和这种“多系列具体对象创建工作”的耦合性。

说明:
这里的程序指客户程序之类的使用者。
简单工厂模式可以用于封装创建实例的实现部分,在应用接口的程序中被广泛使用,其应用模型如图1.16所示。



image

为了处理更加复杂的情况,可以将图中的产品进行再次细分为多个大类,用抽象类进行归纳,完成同大类产品共用代码的复用。然后将工厂类也相应地分为多个大类,用抽象类进行归纳。将图1.16改良后如图1.17所示。



image

说明:

本图假设将A产品和B产品作为两大类产品(即将看作产品的具体实现类再次细分),每大类产品有两个产品,如A产品有A1和A2。
为了说明工厂模式在应用程序中的具体表现,在ch01目录下新建一个程序文件,并命名为Factory.cs,编写代码如程序1.12所示。


22edee24b34d6e18fe1e5fd913ad8dc2c9372829


27d127f6f75880242c5c3ea7605f08bfaa6cf4cb


e0a9c570c5894ac321a034f54aaf8125248d4907

在命令行下编译Factory.cs后,执行Factory程序,其效果如图1.18所示。


f0608310c0d65411f8fd6d682d052b8e289eb546

本例声明了多个类,代码略显复杂,但是只要理解了图1.17,其实也容易掌握。在代码中,首先声明了一个接口,即Ihuman,其中含有两个未实现的方法。实现接口的类是两个抽象类,即Children(孩子)类和Adult(成年人)类,这两个类分别归纳了Boy类和Girl类,以及Man和Woman类。接口的getstatus方法成员在抽象类中实现,而getfav方法则映射为抽象方法,被抽象类的派生类实现。最后通过HumanFactory抽象类的两个派生类,根据不同的参数传递,创建不同的实例引用,并返回接口类型。

在主程序中,分别创建Factory1类和Factory2类的实例(f1和f2),并调用其gethuman方法。根据用户的输入决定创建哪个类的实例引用,并返回一个接口类型引用变量(h1和h2)。接口类型的引用变量调用两个方法时,使用者无法知道方法如何实现、由谁来实现。

【分析】

前面讲解接口的时候,着重分析了Bridge模式,接口可以简单地完成意图与实现的分离,以实现Bridge模式。由于类可以实现多个接口,所以类可以通过多个接口向外界提供多组不同的功能。接口反映了面向对象编程的特征之一,即多态,多态指通过相同方法得到不同的表现。接口也反映了面向对象编程的另一个特征,即封装,使用者并不清楚接口成员实现的细节,如以下代码所示:

interface Ibook             //声明接口Ibook
{
 void read();             //声明未实现的read方法
}
class BookA : Ibook
{
  public void read()         //实现read方法
 {
  Console.WriteLine("你在看A书。");
 }
}
class BookB : Ibook
{
  public void read()         //实现read方法
  {
    Console.WriteLine("你在看B书。");
  }
}
//使用接口的程序代码部分:
 Ibook abc = new BookB();       //创建Ibook类的BookB实例引用
 abc.read();               //调用read方法

接口类型的abc可以引用不同类的实例,以致相同的read方法可以有不同表现。但是以上代码的程序部分中,使用者仍然需要用new运算符进行相应的实例化,同时,使用者还是知道read方法由哪个派生类实现。为了进一步分离意图和实现,并对实现部分更好地封装,简单工厂模式可以进行一定的改良,添加代码如下所示:

class Factory
{
  private Ibook _bka = new BookA();
  private Ibook _bkb = new BookB();
  public Ibook getbook(int i)
  {
    switch (i)
    {
      case 1:
        return _bka;
      case 2:
        return _bkb;        
      default:
        return _bka;
    }
  }
}
//使用接口的程序代码部分修改如下:
Factory f = new Factory();
Ibook abc = f.getbook(2);   //调用f的getbook方法,并传递参数2
abc.read();           //调用read方法

Factory类封装了将接口各个派生类实例化的代码,这样,使用者只需要创建Factory类的实例,并调用getbook方法即可。向getbook方法传递不同的整数类型参数,可以创建不同的实例引用,而这些实例都是Ibook接口类型。如本例中,传递1将创建BookA类的实例引用(Ibook接口类型),传递2将创建BookB类的实例引用(Ibook接口类型)。使用者只知道传递数字来使用接口提供的不同功能,对内部实现却一无所知。Factory类则用于实例化各种类,相当于生产产品的工厂,其产品供接口类型的实例引用,这也是称其为工厂模式的原因。

说明:
本例中工厂类的getbook方法使用switch条件分支判断,然后返回相应的实例引用,在实例种类很多的情况下不大适用。根据具体情况不同,可以考虑利用反射、泛型等方法进行改进。
本文仅用于学习和交流目的,不代表异步社区观点。非商业转载请注明作译者、出处,并保留本文的原始链接。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值