使用带有派生 类 的工厂模式接受不同数量的参数
using the factory pattern with derived classes accepting diverse number of parameters
我正在使用以下 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
}
}
我对工厂模式所做的修改是否破坏了模式,我应该使用不同的模式来创建对象吗?
这个例子有点过于简单化了,但是是的,你可以。
也就是说,这个例子可能会导致一些问题,因为程序员可能对如何使用工厂感到困惑。例如,假设您必须定义一个 GUI 来创建位置:GUI 是否要求用户提供所有 3 个 param
值,即使它们对最初定义的位置没有意义?如果你回答 "Yes" 用户会感到困惑,如果你回答 "No" 那么工厂就不是一个黑盒子了。
我使用这种方法的一个例子是计费;我的应用程序向很多人批量收取了同月的服务费用。有的人按自然天数计费,有的人按劳动天数计费。由于获得劳动日有点慢(它必须咨询数据库以了解当地和国家假期)我缓存它并将它传递给需要它的实例。
有点像 (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:问题不在于构造函数具有不同的参数,而是在您的示例中,您强迫客户端提供可能没有意义的数据。
下面的代码将使用 Position class 中的默认构造函数。
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";
}
}
}
我没有足够的上下文来建议一个好的替代方案,但你的示例使用起来不舒服:工厂模式的想法是封装对象的创建,但由于你对不同的对象有不同的参数集,您必须知道具体实现之间的一些差异,否则您每次都必须提供无用的数据。也许只使用构造函数更好?
工厂的用途是将如何创建对象的需求抽象出来,让客户端在不需要知道如何创建对象的细节的情况下请求对象 .
该模式最 classic 的用途之一是让应用程序根据可能 return MSSQL、SQLite、MySQL 等的密钥创建数据库连接, 联系。客户端不关心实现是什么,只要它支持所有必需的操作。
所以客户端应该完全不知道所需的参数。
操作方法如下。
我稍微扩展了 Position
classes:
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
class 这样的:
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
打印到控制台。
我正在使用以下 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
}
}
我对工厂模式所做的修改是否破坏了模式,我应该使用不同的模式来创建对象吗?
这个例子有点过于简单化了,但是是的,你可以。
也就是说,这个例子可能会导致一些问题,因为程序员可能对如何使用工厂感到困惑。例如,假设您必须定义一个 GUI 来创建位置:GUI 是否要求用户提供所有 3 个 param
值,即使它们对最初定义的位置没有意义?如果你回答 "Yes" 用户会感到困惑,如果你回答 "No" 那么工厂就不是一个黑盒子了。
我使用这种方法的一个例子是计费;我的应用程序向很多人批量收取了同月的服务费用。有的人按自然天数计费,有的人按劳动天数计费。由于获得劳动日有点慢(它必须咨询数据库以了解当地和国家假期)我缓存它并将它传递给需要它的实例。
有点像 (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:问题不在于构造函数具有不同的参数,而是在您的示例中,您强迫客户端提供可能没有意义的数据。
下面的代码将使用 Position class 中的默认构造函数。
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";
}
}
}
我没有足够的上下文来建议一个好的替代方案,但你的示例使用起来不舒服:工厂模式的想法是封装对象的创建,但由于你对不同的对象有不同的参数集,您必须知道具体实现之间的一些差异,否则您每次都必须提供无用的数据。也许只使用构造函数更好?
工厂的用途是将如何创建对象的需求抽象出来,让客户端在不需要知道如何创建对象的细节的情况下请求对象 .
该模式最 classic 的用途之一是让应用程序根据可能 return MSSQL、SQLite、MySQL 等的密钥创建数据库连接, 联系。客户端不关心实现是什么,只要它支持所有必需的操作。
所以客户端应该完全不知道所需的参数。
操作方法如下。
我稍微扩展了 Position
classes:
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
class 这样的:
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
打印到控制台。