更新我已更新示例以更好地说明我的问题。我意识到它缺少一个特定点 - 即CreateLabel()
方法始终采用标签类型,因此工厂可以决定要创建的标签类型。事实上,它可能需要获得更多或更少的信息,具体取决于它想要返回的标签类型。
我有一个工厂类,它返回表示要发送到打印机的标签的对象。
工厂类看起来像这样:
public class LargeLabel : ILabel
{
public string TrackingReference { get; private set; }
public LargeLabel(string trackingReference)
{
TrackingReference = trackingReference;
}
}
public class SmallLabel : ILabel
{
public string TrackingReference { get; private set; }
public SmallLabel(string trackingReference)
{
TrackingReference = trackingReference;
}
}
public class LabelFactory
{
public ILabel CreateLabel(LabelType labelType, string trackingReference)
{
switch (labelType)
{
case LabelType.Small:
return new SmallLabel(trackingReference);
case LabelType.Large:
return new LargeLabel(trackingReference);
}
}
}
假设我创建了一个名为CustomLabel的新标签类型。我想从工厂返回,但需要一些额外的数据:
public class CustomLabel : ILabel
{
public string TrackingReference { get; private set; }
public string CustomText { get; private set; }
public CustomLabel(string trackingReference, string customText)
{
TrackingReference = trackingReference;
CustomText = customText;
}
}
这意味着我的工厂方法必须改变:
public class LabelFactory
{
public ILabel CreateLabel(LabelType labelType, string trackingReference, string customText)
{
switch (labelType)
{
case LabelType.Small:
return new SmallLabel(trackingReference);
case LabelType.Large:
return new LargeLabel(trackingReference);
case LabelType.Custom:
return new CustomLabel(trackingReference, customText);
}
}
}
我不喜欢这样,因为工厂现在需要满足最低的公分母,但同时CustomLabel类需要来获取自定义文本值。我可以提供额外的工厂方法作为覆盖,但我想强制执行CustomLabel需要值的事实,否则它只会被赋予空字符串。
实施此方案的正确方法是什么?
答案 0 :(得分:5)
那么,你想如何调用工厂方法?
专注于您希望如何使用您的API,并且实施通常会使自己相当清楚。如果您将API的所需结果写为单元测试,则可以更轻松地完成此任务。
过载可能是正确的做法,但这实际上取决于你想如何使用工厂。
答案 1 :(得分:2)
如何使用Factory方法确定您需要的标签?
public class LabelFactory {
public ILabel CreateLabel(string trackingReference, string customText) {
return new CustomLabel(trackingReference, customText);
}
public ILabel CreateLabel(String trackingReference) {
return new BasicLabel(trackingReference);
}
}
您的工厂仍然需要了解每种类型(尽管您可以使用接口实现动态加载)但客户端需要知道的很少 - 根据提供的数据,工厂会生成正确的实现。 / p>
这是您所描述的简单问题的简单解决方案。我认为问题是对一个更复杂问题的过度简化,但不知道你的真正问题是什么,我宁愿不设计过于复杂的解决方案。
答案 2 :(得分:1)
这可能表明工厂模式不适合您。但是,如果您确实需要或希望坚持使用它,我建议创建可以传递到工厂的初始化类/结构,而不是字符串。是否要使用基本信息类的各种子类(基本上创建模仿标签类的初始化类层次结构)或者包含所有信息的一个类由您决定。
答案 3 :(得分:1)
您应该尝试使用配置类并将其实例传递给工厂。配置类将构建一个层次结构,其中将为您希望从工厂获得的每个结果存在一个特殊的配置类。每个配置类都会捕获工厂结果的特定属性。
对于您给出的示例,我将编写BasicLabelConfiguration和从中派生的CustomLabelConfiguration。 BasicLabelConfiguration捕获跟踪引用,而CustomLabelConfiguration捕获自定义文本。
最后,工厂根据传递的配置对象的类型做出决定。
以下是代码示例:
public class BasicLabelConfiguration
{
public BasicLabelConfiguration()
{
}
public string TrackingReference { get; set; }
}
public class CustomLabelConfiguration : BasicLabelConfiguration
{
public CustomLabelConfiguration()
{
}
public string CustomText { get; set; }
}
public class LabelFactory
{
public ILabel CreateLabel(BasicLabelConfiguration configuration)
{
// Possibly make decision from configuration
CustomLabelConfiguration clc = configuration as CustomLabelConfiguration;
if (clc != null)
{
return new CustomLabel(clc.TrackingReference, clc.CustomText);
}
else
{
return new BasicLabel(configuration.TrackingReference);
}
}
}
最后你会像这样使用工厂:
// Create basic label
ILabel label = factory.CreateLabel(new BasicLabelConfiguration
{
TrackingReference = "the reference"
});
或
// Create basic label
ILabel label = factory.CreateLabel(new CustomLabelConfiguration
{
TrackingReference = "the reference",
CustomText = "The custom text"
});
答案 4 :(得分:1)
如果没有进一步的信息,很难给出任何建议,但假设工厂模式是您真正需要的,您可以尝试以下方法:
将所需的参数打包在某种属性映射中(例如,字符串映射到字符串),并将其作为参数传递给工厂的create方法。使用众所周知的标记作为地图中的关键字,允许专业工厂根据自己的喜好提取和解释映射的值。
这至少可以让你暂时维护一个工厂界面,并且如果(或什么时候)你发现工厂模式不是正确的,那么推迟处理架构问题。
(哦,如果你真的想在这里使用工厂模式,我强烈建议你让它可插拔,以避免为每种新标签类型修改工厂。)
答案 5 :(得分:1)
您正试图将模式强制进入不适合的场景。我建议放弃这个特定的模式,而不是让最简单的解决方案成为可能。
我认为在这种情况下,我只有一个类Label,它有一个自定义文本的文本字段,通常为空/空,但如果标签需要自定义,可以设置。它简单,不言自明,不会给维护程序员带来任何噩梦。
public class Label
{
public Label(string trackingReference) : this(trackingReference, string.Empty)
{
}
public Label(string trackingReference, string customText)
{
CustomText = customText;
}
public string CustomText ( get; private set; }
public bool IsCustom
{
get
{
return !string.IsNullOrEmpty(CustomText);
}
}
}
答案 6 :(得分:1)
问题更新后的答案更新 - 见下文
我仍然认为您正确使用Factory模式,并在重载CreateLabel方法时更正;但我认为在将LabelType传递给CreateLabel方法时,您忽略了使用Factory模式的重点。
关键点:Factory模式的整个目的是封装选择哪个具体子类进行实例化和返回的逻辑。调用代码不应该告诉Factory要实例化哪个类型。这样做的好处是调用工厂的代码可以避免将来对该逻辑的更改,也可以防止将新的具体子类添加到工厂。您需要的所有调用代码都是Factory,以及从CreateLabel返回的Interface类型。
您调用Factory的代码中的逻辑当前必须看起来像这样的伪代码......
// Need to create a label now
ILabel label;
if(we need to create a small label)
{
label = factory.CreateLabel(LabelType.SmallLabel, "ref1");
}
else if(we need to create a large label)
{
label = factory.CreateLabel(LabelType.LargeLabel, "ref1");
}
else if(we need to create a custom label)
{
label = factory.CreateLabel(LabelType.CustomLabel, "ref1", "Custom text")
}
...所以你明确告诉工厂要创建什么。这很糟糕,因为每次向系统添加新标签类型时,您都需要......
但是,如果将选择LabelType值的逻辑移动到工厂中,则可以避免这种情况。逻辑与其他所有内容一起封装在工厂中。如果系统中添加了新类型的标签,则只需更改工厂。调用工厂的所有现有代码保持不变,没有重大变化。
您当前的调用代码用于确定是否需要大标签或小标签的数据是什么?该数据应该传递给工厂的CreateLabel()方法。
您的工厂和标签类可能如下所示......
// Unchanged
public class BasicLabel: ILabel
{
public LabelSize Size {get; private set}
public string TrackingReference { get; private set; }
public SmallLabel(LabelSize size, string trackingReference)
{
Size = size;
TrackingReference = trackingReference;
}
}
// ADDED THE NULL OR EMPTY CHECK
public class CustomLabel : ILabel
{
public string TrackingReference { get; private set; }
public string CustomText { get; private set; }
public CustomLabel(string trackingReference, string customText)
{
TrackingReference = trackingReference;
if(customText.IsNullOrEmpty()){
throw new SomeException();
}
CustomText = customText;
}
}
public class LabelFactory
{
public ILabel CreateLabel(string trackingReference, LabelSize labelSize)
{
return new BasicLabel(labelSize, trackingReference);
}
public ILabel CreateLabel(string trackingReference, string customText)
{
return new CustomLabel(trackingReference, customText);
}
}
我希望这有用。
答案 7 :(得分:0)
通过阅读您的问题,听起来您的UI收集信息,然后使用工厂创建适当的标签。我们在开发的CAD / CAM应用程序中使用了不同的方法。
在启动期间,我的应用程序使用工厂方法创建标签的主列表。 我的一些标签有初始化参数,因为它们是彼此的变体。例如,我们有三种类型的扁平部件标签。而其他参数则具有用户定义或在设置时未知的参数。
在第一种情况下,初始化在工厂方法中处理。所以我创建了三个FlatPartLabel实例,传递了所需的参数。
在第二种情况下,Label接口有一个configure选项。这将由标签打印机对话框调用以填充设置面板。在您的情况下,这是传递跟踪引用和CustomText的位置。
我的标签界面还为每种Label类型返回一个唯一的ID。如果我有一个特定的命令来处理这种类型的标签,那么我将遍历我的应用程序中的标签列表,找到哪个与ID匹配,将其转换为特定类型的标签,然后进行配置。当用户想要仅为特定的平面部件打印一个标签时,我们这样做。
这样做意味着您可以在标签所需的参数中任意复杂,而不会给您的工厂带来不必要的参数负担。