- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
根据定义“设计模式:抽象工厂”。通知 IT。原始存档于 2009-10-23。检索于 2012-05-16,Object Creational -> Abstract Factory:.
Intent: Provide an interface for creating families of related or dependent objects without specifying their concrete classes."
下面是我对抽象设计模式的尝试。这是我第一次接触工厂方法。谁能帮我解决这个问题。
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));
}
}
}
最佳答案
这是一个虚构的例子(至少在我看来是这样),所以很难给出真正有用的建议,但我立即想到了一些东西:那个冗长的错误倾向 switch
语句。
首先,不要认为要遵循此模式,您必须使用接口(interface)。抽象基类也很好,更好用的是已经在数以千计的论坛、帖子和教程中讨论过的广泛主题。
为了理解为什么 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();
}
}
}
这段代码有什么问题?
您正在抛出错误的异常类型,因为未知 或无效 枚举
值您应该使用InvalidEnumArgumentException
:
throw new InvalidEnumArgumentException("Unknown product type.", type, typeof(ProductType));
第二个错误是将不同的东西放在同一个枚举中。你有肥皂和蜡。它们完全不相关,您甚至可以使用两种不同的工厂方法来创建它们。这是令人困惑的(在更复杂的情况下,当您有一个 ProductType
参数时,您可能希望可以自由使用它们)然后让我们拆分它们:
public enum SoapTypes {
Beauty,
Detergent
}
您的工厂方法将是:
public ISoap Create(SoapType type)
请注意,您甚至不需要为您的方法使用不同的名称,因为您现在拥有不同的参数类型。您的默认案例现在将仅针对未知值(您将新项目添加到 SoapType
但您忘记更新代码)或明显错误的用法(例如调用Create((SoapType)100)
其中 100 不是文字 (!!!) 值,但它是在某处计算/读取的)。
现在假设您添加了一种新产品类型,您必须执行所有这些操作:
ISoap
。ProductType
添加一个新值。您比必要的步骤多了一步。理想情况下,每个更改应该只影响代码中的一个位置,在这里您无法避免前两个步骤,但第三个可能是多余的。您的选择不多。
如果此代码对性能至关重要(度量!),您可以使用字典来获得更具可读性的代码(IMO):
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);
}
例如,
FactoryClassAttribute
就是这个(请注意,此代码可能会被极大地概括)。注意 enum constants are fields :
[Serializable]
sealed class FactoryClassAttribute : Attribute {
public FactoryClassAttribute(Type type) {
Type = type;
}
public Type Type { get; set; }
public static FactoryClassAttribute From(Enum value) {
{
var type = value.GetType();
return type.GetField(Enum.GetName(type, value))
.GetCustomAttributes(false)
.OfType<FactoryClassAttribute>()
.FirstOrDefault();
}
}
关于c# - 这是否遵循抽象工厂模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32736250/
我应该执行以下操作: 可能通过服务/工厂,使用 $q(异步)查询 API 以获取大型名称数据集 有另一个服务(也是异步的),它应该只返回上述工厂的元素,如果它们与某个字符串(搜索字段)匹配。目的是缩小
我有一个通用的基类。我有一个实现基类的具体类。 我将如何创建工厂类/方法来交付不同类型的具体类? 举个例子: public class ReceiverBase where T : IInte
我正在查看以下链接中的 Ninject Factory 扩展: http://www.planetgeek.ch/2011/12/31/ninject-extensions-factory-intro
工厂、提供商和服务这三个术语之间有什么区别? 刚刚了解 NHibernate 及其存储库模式(POCO 类等)。 最佳答案 工厂:通过将一堆位组合在一起或基于某种上下文选择类型来组装类 Provide
使用CGLIB我可以做到 final var enhancer = new Enhancer(); enhancer.setUseCache(false); enhancer.setSuperclas
我试图在 Kotlin 中使用伴随对象工厂方法(相当于 Java 中的静态工厂方法)创建一个嵌套内部类。这是我的代码的简化版本。 class OuterClass { var myData:L
我正在为我的大学做一个项目,但遇到了问题。 基本上,该项目由一个客户端-服务器应用程序组成,我想创建一个用于通信的 Packet 类。数据包由 header 和主体组成。现在问题来了。我可以有一些不同
这个问题在这里已经有了答案: Why doesn't polymorphism work without pointers/references? (6 个答案) What is object sl
我正在制作一个套接字工厂。我希望每个外部应用程序都使用 Socket 类的接口(interface),它是几个类(ServerSocketTCP、ClientSocketTCP、ServerSocke
我是 angularjs 的新手,我正在尝试创建一个小型电影数据库。这是我第一次使用工厂,我想确保这是正确的方法,以及如何在另一个功能中使用这个工厂,如下所示? 我希望这个工厂只运行一次,这样我就可以
这个问题在这里已经有了答案: Java inner class and static nested class (28 个答案) 关闭 5 年前。 public class DataFactory
我看过很多关于 C++ 工厂的帖子,但到目前为止我还没有看到解决我的问题的解决方案。 (虽然我可能遗漏了一些东西。) 示例控制台应用程序: #include #include #include
这是一个简单的 C++ 项目,有 2 种设计模式:单例和工厂,sigleton 也是一个模板化类,一个接口(interface) (IHash) 和一个类 (Hash1)。一个简单的工厂类 (Hash
这个问题类似于Factory and generics ,并且可能有相同的答案,但它是不同的。我有一个通用基类,它将由完全独立的 JAR 中的类进行扩展。所述 JAR 应该能够在不更改任何其他代码的情
问题是我需要为传递的类创建一个新实例 有没有办法重写这个函数,让它可以接受任意数量的参数? function createInstance(ofClass, arg1, arg2, arg3, ...
我想用简单的 C++ 语法创建一个简单的工厂方法: void *createObject(const char *str,...) { if(!strcmp("X",str)) retu
经过大约 10 个月的程序化 PHP 学习后,我现在正尝试着手研究基本的 OOP 原则和设计模式。这是一个爱好,我没有那么多时间去追求它,所以请原谅这个问题的水平很低。 我的网站(目前 100% 程序
我有一个简单的问题。 我如何编写一个工厂来定义使用 make() 或 create() 的关系,具体取决于原始调用 make() 还是 create()? 这是我的用例: 我有一个简单的工厂 /**
我正在尝试在延迟加载模块中提供 APP_BASE_HREF 注入(inject) token ,然而,工厂方法根本没有被调用。 在这里https://github.com/MaurizioCascia
我有以下 ast: import { factory as f } from 'typescript' const typeDeclaration = f.createTypeAliasDeclara
我是一名优秀的程序员,十分优秀!