为什么我们已经有具体工厂时需要抽象工厂

时间:2019-09-10 02:59:37

标签: c# .net design-patterns

这是文章

https://www.codeproject.com/Articles/328373/Understanding-and-Implementing-Abstract-Factory-Pa

我不知道为什么我们需要像客户IPhoneFactory这样的抽象工厂,我们不能像

class PhoneTypeChecker
{
   ISmart sam;
   IDumb htc;
   //IPhoneFactory factory;    get rid of this abstract factory
   MANUFACTURERS manu;

   ...
   public void CheckProducts()
    {
        switch (manu)
        {
            case MANUFACTURERS.SAMSUNG:
                Console.WriteLine(new SamsungFactory().GetSmart().Name()); 
                Console.WriteLine(new SamsungFactory().GetDumb().Name());               
                break;
            case MANUFACTURERS.HTC:
                Console.WriteLine(new HTCFactory().GetSmart().Name());  
                Console.WriteLine(new HTCFactory().GetDumb().Name());               
                break;
            case MANUFACTURERS.NOKIA:
                Console.WriteLine(new NokiaFactory().GetSmart().Name()); 
                Console.WriteLine(new NokiaFactory().GetDumb().Name());                
                break;
        }

        Console.WriteLine(manu.ToString() + ":\nSmart Phone: " + 
        factory.GetSmart().Name() + "\nDumb Phone: " + factory.GetDumb().Name());
    }
}

我唯一想到使用IPhoneFactory的地方是,我们需要从具体的工厂类中获得两种不同的类型(智能和哑巴),但是它只保存了一些击键,对吗?

1 个答案:

答案 0 :(得分:2)

与您链接的文章存在一个中心问题,这意味着它没有提供一个很好的示例来说明如何使用抽象工厂来使应用程序更具扩展性:

问题在于enum Manufacturersclass PhoneTypeChecker.CheckProducts都必须了解所有类型的制造商。这几乎完全破坏了抽象工厂模式的目的(除非您将CheckProducts()解释为“抽象工厂工厂”方法-在这种情况下为welcome to Enterprise Java hell

...但是,如果我们对组成进行一些调整,优势将变得显而易见。

首先,删除enum MANUFACTURER(无论如何都不应该大写)和CheckProducts,然后将其替换为IManufacturerRepository

  • 重要说明:如果您实际上是在编写与ORM交互的真实代码,则请勿创建自己的存储库类型,因为您的ORM为以下内容提供了存储库:您。对于实体框架尤其如此。尤其要避免使用“通用存储库”反模式。

IManufacturerRepository应该只有一个实现(或用于测试/模拟的单独实现)。

public interface IManufacturerRepository
{
    List<IManufacturer> GetManufacturers();
}

public interface IManufacturer
{
    String        Name         { get; }
    IPhoneFactory PhoneFactory { get; } // <-- this is the abstract factory
}

然后PhoneTypeChecker可以通过构造函数参数接收IManufacturer

  • 我注意到这个示例很愚蠢,因为PhoneTypeChecker内部没有有意义的实例状态突变,PhoneTypeChecker也不代表由抽象类型或接口表示的任何类型的操作-最好这样做CheckProducts一种static方法,该方法接受IManufacturer作为参数。)
  • 在原始文章中,CheckProducts方法确实改变了PhoneTypeChecker的状态(通过设置factorysamhtc),但是这是一个糟糕的设计-因为它实际上只是在初始化自身,应该在构造函数内部完成-但我离题了。

无论如何:

public class PhoneTypeChecker
{
    private readonly IManufacturer mfg;

    public PhoneTypeChecker( IManufacturer mfg )
    {
        this.mfg = mfg ?? throw new ArgumentNullExceptio(nameof(mfg));
    }

    public void CheckProducts()
    {
        Console.WriteLine( this.mfg.Name + ":\nSmart Phone: " + 
    this.mfg.PhoneFactory.GetSmart().Name() + "\nDumb Phone: " + this.mfg.PhoneFactory.GetDumb().Name() );
    }
}

然后将Main方法重做为:

static void Main(string[] args)
{
    IManufacturerRepository repo = new ActualIManufacturerRepository();
    List<IManufacturer> mfgs = repo.GetManufacturers();

    PhoneTypeChecker checker = new PhoneTypeChecker( mfgs.Single( m => m.Name == "Samsung" ) );

    checker.CheckProducts();

    Console.ReadLine();

    checker = new PhoneTypeChecker( mfgs.Single( m => m.Name == "HTC" ) );

    checker.CheckProducts();
    Console.ReadLine();

    checker = new PhoneTypeChecker( mfgs.Single( m => m.Name == "Nokia" ) );

    checker.CheckProducts();
    Console.Read();
}

此示例还有其他问题-因此,请勿以该示例为例来编写结构良好或具有生产质量的代码。

简而言之:只有IManufacturerRepository的实现应该知道IManufacturer的实际实现(并且只有IManufacturer的实现应该知道{{1}的实现) }。