我使用以下factory pattern:
using System;
class Program
{
abstract class Position
{
public abstract string Title { get; }
}
class Manager : Position
{
public override string Title
{
get
{
return "Manager";
}
}
}
class Clerk : Position
{
public override string Title
{
get
{
return "Clerk";
}
}
}
class Programmer : Position
{
public override string Title
{
get
{
return "Programmer";
}
}
}
static class Factory
{
/// <summary>
/// Decides which class to instantiate.
/// </summary>
public static Position Get(int id)
{
switch (id)
{
case 0:
return new Manager();
case 1:
case 2:
return new Clerk();
case 3:
default:
return new Programmer();
}
}
使用此模式的方法来自同一来源的示例:
static void Main()
{
for (int i = 0; i <= 3; i++)
{
var position = Factory.Get(i);
Console.WriteLine("Where id = {0}, position = {1} ", i, position.Title);
}
}
如果我的派生类为其构造函数使用不同数量的参数,我是否应该使用此模式?
我需要做的可能的修改是在实例化工厂时:
var position = Factory.Get(i);
我可能需要传递所有派生类的参数,无论它们是否会使用它们:
var position = Factory.Get(i, param1, param2, param3);
并且需要修改switch语句:
public static Position Get(int id, param1, param2, param3) //HERE IS THE MODIFIED PARAM LIST
{
switch (id)
{
case 0:
return new Manager(param1); //MODIFIED
case 1:
case 2:
return new Clerk(param2, param3); //MODIFIED
case 3:
default:
return new Programmer(param3); //MODIFIED
}
}
我对工厂模式所做的修改是否会破坏模式,我应该使用不同的模式来创建对象吗?
答案 0 :(得分:1)
这个例子太过愚蠢,但是,你可以。
那就是说,这个例子可能会导致一些问题,因为程序员可能会对如何使用工厂感到困惑。例如,假设您必须定义一个GUI来创建位置:GUI是否会询问用户所有3个param
值,即使它们对首先定义的位置没有意义?如果你回答“是”,用户会感到困惑,如果你回答“否”,那么工厂就不应该是一个黑盒子了。
我使用这种方法的一个例子是计费;我的申请将同月的服务按批次计费给很多人。有些人按月份的自然天数收费,有些人按可用日数收费。由于获得可用的日子有点慢(它必须在本地和国家假日咨询数据库)我缓存它并将其传递给需要它的实例。
就像(Java):
public class BillerFactory {
private HashMap<Date, ListOfHolidaysInMonth> holidayCache =
new HashMap<>();
...
public getBiller(BillingType billingType, Date firstOfMonth) {
switch (billingType) {
case BillingType.NATURAL:
return new NaturalBiller(firstOfMonth);
case BillingType.LABORAL:
ListOfHoliday holidays = this.holidayCache.get(firstOfMonth);
if (holidays == null) {
holidays = this.calculateHolidays(firstOfMonth);
holidayCache.put(firstOfMonth, holidays);
}
return new LaboralBiller(firstOfMonth, holidays);
}
}
TLDR:问题不在于构造函数有不同的参数,但在您的示例中,您强制客户端提供可能没有意义的数据。
答案 1 :(得分:1)
下面的代码将使用Position类中的默认构造函数。
static void Main(string[] args)
{
Manager mngr = new Manager();
}
}
public abstract class Position
{
public abstract string Title { get; }
public Position()
{
}
}
public class Manager : Position
{
public override string Title
{
get
{
return "Manager";
}
}
}
答案 2 :(得分:1)
我没有足够的背景建议一个好的选择,但你的样本使用起来不舒服:工厂模式的想法是封装对象的创建,但因为你有一个不同的集合对于不同对象的参数,您必须知道具体实现之间的一些差异,或者您必须每次都提供无用的数据。也许只使用构造函数会更好吗?
答案 3 :(得分:1)
工厂的使用是抽象出如何创建对象的要求,以便允许客户端询问对象,而无需了解的详细信息。
该模式最常见的用途之一是让应用程序基于可能返回MSSQL,SQLite,MySQL等连接的密钥创建数据库连接。只要它支持所有必需的操作,客户端就不关心实现是什么。
因此,客户端应该完全不知道所需的参数。
这是怎么做的。
我稍微扩展了Position
类:
abstract class Position
{
public abstract string Title { get; }
}
class Manager : Position
{
public Manager(string department) { }
public override string Title => "Manager";
}
class Clerk : Position
{
public override string Title => "Clerk";
}
class Programmer : Position
{
public Programmer(string language) { }
public override string Title => "Programmer";
}
现在我已经创建了这样的Factory
类:
static class Factory
{
private static Dictionary<int, Func<Position>> _registry =
new Dictionary<int, Func<Position>>();
public static void Register(int id, Func<Position> factory)
{
_registry[id] = factory;
}
public static Position Get(int id)
{
return _registry[id].Invoke();
}
}
然后它变得易于使用工厂。当您初始化应用程序时,您将编写此类代码:
Factory.Register(1, () => new Manager("Sales"));
Factory.Register(2, () => new Clerk());
Factory.Register(3, () => new Programmer("C#"));
现在,稍后,当客户端代码想要一个Position
对象时,它只需要这样做:
var position = Factory.Get(3);
在我输出position.Title
的测试中,我将Programmer
打印到控制台。