哪种方式使用 Factory 更好(正确)?
IPacket info = PacketFactory.CreatePacketObject(PacketType.Info, currentUser, DateTime.Now, " disconnected");
或者我应该放弃 PacketFactory 中的第二种方法并使用这个方法?
IPacket info = PacketFactory.CreatePacketObject(PacketType.Info);
info.CreationTime = DateTime.Now;
info.Creator = currentUser;
info.Data = " disconnected";
或者其他的?
PacketFactory 代码:
public static class PacketFactory
{
public static IPacket CreatePacketObject(PacketType type)
{
IPacket packetToCreate = null;
switch (type)
{
case PacketType.Info:
packetToCreate = new Info();
break;
case PacketType.Log:
packetToCreate = new Log();
break;
case PacketType.Message:
packetToCreate = new Message();
break;
}
return packetToCreate;
}
public static IPacket CreatePacketObject(PacketType type, Client creator, DateTime creationTime, string data)
{
IPacket packetToCreate = null;
switch (type)
{
case PacketType.Info:
packetToCreate = new Info(creator, creationTime, data);
break;
case PacketType.Log:
packetToCreate = new Log(creator, creationTime, data);
break;
case PacketType.Message:
packetToCreate = new Message(creator, creationTime, data);
break;
}
return packetToCreate;
}
}
最佳答案
在应用模式之前,您应该清楚地了解这样做的好处,在这种情况下,我真的不认为引入静态“工厂”会给您带来任何好处。从 PacketFactory
的客户端的角度来看:引入它是否降低了客户端与 IPacket
的各种具体实现者之间的耦合?我认为不会,因为客户端已经必须通过指定 IPacket
、 PacketType.Info
或 PacketType.Message
的枚举值来知道它想要哪种 PacketType.Log
。这与了解 Info
、 Message
和 Log
类的客户端有何不同?由于“工厂”是一个静态类,因此客户端与返回的 IPacket
类型耦合,就像它只是调用适当的 IPacket
实现者的构造函数一样,因为您必须更改客户端才能使其在任何一种情况下都使用不同类型的 IPacket
。
所以,如果你真的必须使用某种工厂,那么我建议使用抽象工厂模式,这样工厂的客户将只依赖于工厂接口(interface),因此能够使用不同类型的 IPacket
无需更改。例如:
public interface IPacketFactory
{
IPacket CreatePacket();
IPacket CreatePacket(Client creator, DateTime creationTime, string data);
}
public class MessageFactory : IPacketFactory
{
public CreatePacket()
{
return new Message();
}
public CreatePacket(Client creator, DateTime creationTime, string data)
{
return new Message(creator, creationTime, data);
}
}
//You'd implement factories for each IPacket type...
public class Client
{
private IPacketFactory _factory;
public Client(IPacketFactory factory)
{
_factory = factory;
}
public SomeMethodThatNeedsToCreateIPacketInstance()
{
IPacket packet = _factory.CreatePacket();
//work with packet without caring what type it is
}
}
//a higher level class or IOC container would construct the client with the appropriate factory
Client client = new Client(new MessageFactory());
// the Client class can work with different IPacket instances without it having to change (it's decoupled)
Client client2 = new Client(new LogFactory());
至于工厂是否应该允许在不指定创建者、数据和创建时间的情况下构造一个 IPacket
取决于类的不变量。如果在未指定字段时可以满足类不变量,那很好,否则它们应该是必需的。类的一部分工作应该是确保它不会以无效状态构建,因为类的用户将视情况而定。
在 IPacket
实现者之一需要额外参数的情况下:
抽象工厂模式需要为所有实现者提供一个统一的接口(interface),因此如果所有工厂都有一个带有额外参数的 Create 方法是有意义的,那么您可以将它们添加到接口(interface)中。一种形式是传递一个具有各种属性/方法的对象,Create
方法可以使用这些属性/方法来派生它需要的额外参数值。一种特殊情况是 Double Dispatch,其中调用者传递自身(在本例中为 Client),然后从 Create 方法内部调用。
//in MessageFactory : the PacketContext holds various data that may be relevant to creation
public IPacket Create(Client creator, DateTime creationTime, string data, PacketContext ctx)
{
return new Message(creator, creationTime, data, ctx.SomeExtraData);
}
//in LogFactory: the Log doesn't need anything from the PacketContext but it does call something on the Client (Double Dispatch)
public IPacket Create(Client creator, DateTime creationTime, string data, PacketContext ctx)
{
return new Log(creator.Name, creationTime, data);
}
您需要记住,目标是抽象正在创建的 IPacket
的类型,因此如果在实现此方法时您开始感觉到 Client
开始隐含地知道正在构造的特定类型,那么您可能必须退后一步,考虑工厂是否合适。您唯一的其他选择是在构建工厂时提供额外信息(即将其传递给构造函数)。
public class MessageFactory : IPacketFactory
{
private object _data;
public MessageFactory(object extraData)
{
_data = extraData;
}
IPacket CreatePacket(Client creator, DateTime creationTime, string data)
{
return new Message(creator, creationTime, data, _extraData);
}
///rest of implementation
}
这些代表了一些选项,但无论如何,我强烈建议您不要使用静态或单例“工厂”类,因为它会将您的客户端类与工厂紧密耦合,很可能是 IPacket
子类.
关于c# - 工厂模式的使用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7945541/