zoukankan      html  css  js  c++  java
  • [C#]抽象工厂模式的几种实现方法及比较

    利用设计模式可以使我们的代码更灵活,更容易扩展,更容易维护。各种面向对象的程序设计语言都提供了基本相同的机制:比如类、继承、派生、多态等等。但是又有各自的特色,C# 中的反射机制便是一个很重要的工具,好好地利用就可以在实际中发挥很大的作用。

    我们来看一个例子:

    我的程序中有需要一系列的对象,比如apple,orange…, 要想利用他们,我们就必须在程序中根据用户要求,然后一个个调用 new 操作符来生成他们,这样客户程序就要知道相应的类的信息,生成的代码显然不够灵活。我们可以在代码中不利用具体的类,而只是说明我们需要什么,然后就能够得到我们想要的对象吗?

    我们的程序考虑的是对象怎么创建的,创建型模式应该符合要求吧。然后我们浏览一下各模式的“意图”部分。第一个好像就撞到彩了,抽象工厂,我们看看吧,“提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类”,至少“无需指定它们具体的类”符合我们的要求。来看看它的结构吧!

    我们的问题好像用不到这么复杂吧!只有orange,apple等等(应该就是product了),他们显然是一类的,都是fruit,我们只要一个生产水果的工厂就可以,左边的继承层次不要,只有一个FruitFactroy看看行不,先别管它正统不正统,实用就行。

    下面的一些东西显然是我们需要的:

    Public interface IFruit 
    {
    }
    public class Orange:IFruit
    {
      public Orange()
      {
    Console.WriteLine("An orange is got!");
      }
    }
    public class Apple:IFruit
    {
      public Apple()
      {
    Console.WriteLine("An apple is got!");
      }
    }

    我们的FruitFactory应该是怎么样呢?上面的结构图中它给的是CreateProductA,那好,我就MakeOrange,还有一个CreateProductB,俺MakeOrange还不行??

    public class FruitFactory 
    {
      public Orange MakeOrange()
      {
    return new Orange();
      }
      public Apple MakeApple()
      {
    return new Apple();
      }
    }

    怎么使用这个工厂呢?我们来写下面的代码:

    string FruitName = Console.ReadLine(); 
    IFruit MyFruit = null;
    FruitFactory MyFruitFactory = new FruitFactory();
    switch (FruitName)
    {
      case "Orange":
    MyFruit = MyFruitFactory.MakeOrange();
    break;
      case "Apple":
    MyFruit = MyFruitFactory.MakeApple();
    break;
      default:
    break;
    }

    编译运行,然后在控制台输入想要的东西,成功。不过等等,它好像还不完美,我如果想要pear,我既要在客户代码中的switch中加入判断,又要在工厂方法中加入MakePear方法,好像不怎么优雅。更好一点,在工厂中只提供一个方法,MakeFruit,然后传递进一个参数Name,代表我们想要的水果的名称,这样的话,似乎我们的客户代码中的那个switch就可以不要了,相反,在FruitFactory中好像需要一个,还等什么呢?实现吧!

    FruitFactory: 
    public class FruitFactory
    {
      public IFruit MakeFruit(string Name)
      {
    switch (Name)
    {
      case "Orange":
    return new Orange();
      case "Apple":
    return new Apple();
      default:
    return null;
    }
      }
    }

    客户代码:

    string FruitName = Console.ReadLine(); 
    IFruit MyFruit;
    FruitFactory MyFruitFactory = new FruitFactory();
    MyFruit = MyFruitFactory.MakeFruit(FruitName);

    这样看起来好多了,至少我客户代码中不要再写那么一长串的判断代码了。
    既然不要条件判断,传入的只有水果的名称,假如Name = “Apple”,要生成一个Apple的对象,我需要new Apple(),如果我能够这样多好: new MakeItToClass(Name),把字符串转换成一个类。C#中虽然没有上述语法,但是提供了相应的机制,那就是反射。其中一个重要的类就是System.Type类,它对于反射起着核心的作用。我们可以使用 Type 对象的方法、字段、属性和嵌套类来查找有关该类型的所有信息。
    另外一个重要的类就是System.Activator,它包含特定的方法,用以在本地或从远程创建对象类型,或获取对现有远程对象的引用。 
    我们可以先利用Type类获取Name指定的类名的类的Type信息,然后可以根据这个信息利用Activator创建对象。

    public class FruitFactory 
    {
      public IFruit MakeFruit(string Name)
      {
    IFruit MyFruit = null;
    try
    {
      Type type = Type.GetType(Name,true);
      MyFruit = (IFruit)Activator.CreateInstance(type);
    }
    catch (TypeLoadException e)
      Console.WriteLine("I dont know this kind of fruit,exception caught - {0}" ,e.Message);
      return MyFruit;
      }
    }


    -----
  • 相关阅读:
    比赛-ZR DAY1 (04 Aug, 2018)
    Java NIO系列教程(十一) Pipe
    Java NIO系列教程(九) ServerSocketChannel
    Java NIO系列教程(十) Java NIO DatagramChannel
    Java NIO系列教程(七) FileChannel
    Java NIO系列教程(八) SocketChannel
    Java NIO系列教程(六) Selector
    Java NIO系列教程(四) Scatter/Gather
    Java NIO系列教程(五) 通道之间的数据传输
    Java NIO系列教程(二) Channel
  • 原文地址:https://www.cnblogs.com/boneking/p/1382181.html
Copyright © 2011-2022 走看看