这是否遵循抽象工厂模式

时间:2015-09-23 09:50:13

标签: c# oop design-patterns

根据定义"设计模式:抽象工厂"。 InformIT的。从2009-10-23原版存档。检索到2012-05-16,Object Creational - >抽象工厂:

  

意图:提供接口   无需指定即可创建相关或从属对象的族   他们的具体课程。"

以下是我对抽象设计模式的尝试。这是我第一次采用工厂方法。任何人都可以帮我这个。

enum ProductType
{
    BeautySoap = 1,
    DetergentSoap = 2,
    HairWax = 3,
    BodyWax = 4,
}
interface ISoap
{
    string Create(string name);

}
interface IWax
{
    string Create(string name);
}

public class HarWax : IWax
{
    public string Create(string name)
    {
        return string.Format("Hair Wax {0} created", name);
    }
}

public class BodyWax : IWax
{

    public string Create(string name)
    {
        return string.Format("Body wax {0} created", name);
    }
}
public class BeautySoapFactory : ISoap
{
    public string Create(string name)
    {
         return string.Format("Toilet soap {0} created", name);
    }

}
public class DetergentSoapFactory : ISoap
{
    public string Create(string name)
    {
         return string.Format("Detergent bar {0} created", name);
    }
}



//factory of factories(Bike Factory, Scooter Factory)
/// <summary>
/// The 'AbstractFactory' interface. 
/// </summary>
interface IBeautyProduct
{
    ISoap CreateSoap(ProductType type);
    IWax CreateWax(ProductType type);
}

class HULFactory : IBeautyProduct
{
    public ISoap CreateSoap(ProductType type)
    {
        switch (type)
        { 
            case ProductType.BeautySoap:
                return new BeautySoapFactory();
            case ProductType.DetergentSoap:
                return new DetergentSoapFactory();
            default:
                throw new ApplicationException(string.Format("Soap '{0}' cannot be created", type));
                //Console.WriteLine(string.Format("Soap '{0}' cannot be created", name));
                //break;
        }
    }
    public IWax CreateWax(ProductType type)
    {
        switch (type)
        {
            case ProductType.HairWax:
                return new HarWax();
            case ProductType.BodyWax:
                return new BodyWax();
            default:
                throw new ApplicationException(string.Format("Wax '{0}' cannot be created", type));
        }
    }
}

class LotusherbalsFactory : IBeautyProduct
{
    public ISoap CreateSoap(ProductType type)
    {
        switch (type)
        {
            case ProductType.BeautySoap:
                return new BeautySoapFactory();
            case ProductType.DetergentSoap:
                return new DetergentSoapFactory();
            default:
                throw new ApplicationException(string.Format("Soap '{0}' cannot be created", type));
            //Console.WriteLine(string.Format("Soap '{0}' cannot be created", name));
            //break;
        }
    }
    public IWax CreateWax(ProductType type)
    {
        switch (type)
        {
            case ProductType.HairWax:
                return new HarWax();
            case ProductType.BodyWax:
                return new BodyWax();
            default:
                throw new ApplicationException(string.Format("Wax '{0}' cannot be created", type));
        }
    }
}

2 个答案:

答案 0 :(得分:2)

这是一个虚构的例子(至少在我看来)所以很难给出真正有用的建议但是我立刻想到了一些东西:冗长的冗长错误 switch 语句

首先,不要认为要遵循这种模式,必须使用接口。另外一个抽象的基类很好,最好使用的是一个已在千篇论坛,帖子和教程中讨论过的大量话题。

要理解为什么开关不好让我简化你的场景(你有工厂的工厂......),让我们假设你只有一个:

class Factory 
{
    public ISoap CreateSoap(ProductType type)
    {
        switch (type)
        {
            case ProductType.BeautySoap:
                return new BeautySoapFactory();
            case ProductType.DetergentSoap:
                return new DetergentSoapFactory();
            default:
                throw new ApplicationException();
        }
    }
}

此代码中有什么问题?

未知无效 enum错误的异常类型 使用InvalidEnumArgumentException

throw new InvalidEnumArgumentException("Unknown product type.", type, typeof(ProductType));

第二个错误是将不同的东西放在同一个枚举中。你有肥皂和蜡。它们完全不相关,您甚至可以使用两种不同的工厂方法来创建它们。这是令人困惑的(在更复杂的情况下,如果你有一个ProductType参数,你可能希望可以全部使用它们)然后让拆分它们

public enum SoapTypes {
    Beauty,
    Detergent
}

您的工厂方法将是:

public ISoap Create(SoapType type)

请注意,您甚至不需要为您的方法使用不同的名称,因为您现在拥有不同的参数类型。您的默认情况现在仅针对未知值执行(您向SoapType添加新项目,但忘记更新代码)或明显错误使用(例如调用{{1其中100不是&#39; ta文字(!!!)值,但它在某处计算/读取。

现在让我们假设你添加了一个新的产品类型,你必须做所有这些:

  • 创建一个新类来实现Create((SoapType)100)
  • ISoap添加新值。
  • 在您的交换机中添加新案例。

你比我们需要的步骤更多一步。理想情况下,每次更改都应仅影响代码中的一个位置,此处您可以避免前两个步骤,但第三个可能多余。你没什么选择。

如果此代码对性能至关重要(措施!),您可以使用字典来获得更易读的代码(IMO):

ProductType

它看起来更具可读性(对我而言)并且它对动态更改开放(实例化的类可能不会在源文件中进行硬编码,而是来自配置)。如果映射是可配置的,您可能会使用此方法。

但是,您仍需要更新枚举工厂方法/词典。可能他们在不同的源文件中,你可能会忘记一些东西。如果性能不是(测量!)问题,您可能希望将元数据添加到您的枚举值,当您将所有内容放在同一屏幕上时,很难忘记它:< / p>

static Dictionary<SoapType, Type> _soaps = new Dictionary<SoapType, Type>
{
    { SoapType.Beauty, typeof(BeautySoapFactory) }
    { SoapType.Detergent, typeof(DetergentSoapFactory) }
};

public ISoap CreateSoap(SoapType type) {
    return (ISoap)Activator.CreateInstance(_soaps[type]);
}

您的工厂方法将是:

public enum SoapType {
    [FactoryClass(typeof(BeautySoapFactory)] Beauty,
    [FactoryClass(typeof(DetergentSoapFactory)] Detergent,
}
例如,

public ISoap CreateSoap(SoapType type) { var descriptor = FactoryClassAttribute.From(type); return (ISoap)Activator.CreateInstance(descriptor.Type); } 就是这样(请注意,此代码可能会大大推广)。请注意enum constants are fields

FactoryClassAttribute

答案 1 :(得分:1)

您提及抽象工厂工厂方法,然后您拥有此代码,这是简单工厂

public ISoap CreateSoap(ProductType type)
{
    switch (type)
    { 
        case ProductType.BeautySoap:
            return new BeautySoapFactory();
        case ProductType.DetergentSoap:
            return new DetergentSoapFactory();
        default:
            throw new ApplicationException(string.Format("Soap '{0}' cannot be created", type));
            //Console.WriteLine(string.Format("Soap '{0}' cannot be created", name));
            //break;
    }
}
  

任何人都可以帮助我。

这三种设计模式很容易混淆。很难回答你的问题(没有一个明确的问题)。

不是重复答案中的所有三种模式(这将是非常长的),我将引用您对所有三种变体的非常好的解释:

http://corey.quickshiftconsulting.com/blog/first-post

有一些提示可以帮助区分它们:

  • 简单工厂非常常见,通常涉及一种方法(不是多态的!)来基于某种判别式返回子类型。您的CreateSoap()就是一个很好的例子。
  • 工厂方法模式不如简单工厂常见,并且涉及使用多态方法,其中每个子类型返回不同创建类型的实例。一个很好的例子是Java的Collection.iterator()方法。 Collection的子类型(实现)返回与Iterator子类型对应的Collection实现。例如,ArrayList.iterator()将返回一个(隐藏)类型,该类型知道如何迭代ArrayList(与LinkedList不同)。
  • 抽象工厂可能是最不常见的,它涉及产品类型的系列,并且通常依赖于Factory方法来创建子类型。

如果你喜欢披萨,Head First Design Patterns在GitHub上有它的所有代码示例。以下是与您的问题相关的具体示例的链接:

  • Simple Factory
  • Factory Method - PizzaStore.createPizza(...)是各种子类中定义的工厂方法,例如ChicagoPizzaStoreNYPizzaStore
  • Abstract Factory - PizzaIngredientFactory定义了如何制作相关产品系列的界面,例如createDough()createSauce()等。