哪种方式使用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;
}
}
答案 0 :(得分:8)
在应用模式之前,你应该清楚地知道你通过这样做获得了什么,在这种情况下,我并没有真正看到引入静态“工厂”正在获得任何东西。从PacketFactory
的客户端的角度来看它:引入它减少了客户端与IPacket
的各种具体实现者之间的耦合?我不认为,因为客户已经必须通过指定IPacket
,PacketType.Info
或PacketType.Message
的枚举值来了解它所需要的PacketType.Log
。与客户了解Info
,Message
和Log
类有什么不同?由于“Factory”是一个静态类,因此客户端与正在返回的IPacket
类型相同,如果它只调用相应IPacket
实现者的构造函数,因为它必须更改客户端,以便在任何一种情况下都使用不同类型的IPacket
。
所以,如果你真的必须使用某种类型的工厂,那么我建议使用抽象工厂模式,以便工厂的客户只依赖于工厂界面,因此能够使用不同种类的{ {1}}无需更改。例如:
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
实现者需要额外的参数:
抽象工厂模式需要为所有实现者提供统一的接口,因此如果所有工厂都有一个带有额外参数的Create方法,那么您可以将它们添加到接口。其中一种形式是传递具有各种属性/方法的对象,IPacket
方法可以使用它来获得所需的额外参数值。一个特殊情况是Double Dispatch,其中调用者自己传递(在本例中为Client),然后从Create方法内部调用。
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
那些代表了一些选项,但无论如何,我强烈建议您不要使用静态或单例“Factory”类,因为它会将您的客户端类强烈地耦合到工厂,很可能是{{ 1}}子类。
答案 1 :(得分:3)
IMO取决于是否需要CreationTime,Creator和Data来创建数据包的有效实例。如果是这样的话,我会坚持使用解决方案之一并要求尽可能早地设置这些属性,在您的工厂方法中。如果不应该在以后的某个时刻更改这些属性,我还会另外制作这些属性。 如果设置属性是可选的,请保持工厂界面清洁并删除具有属性的重载。
答案 2 :(得分:1)
我建议第一种方法是这样的
IPacket
属性标记为只读,所有实例都将是不可变的Create..()
工厂方法中构建一个对象,而不是通过做一个必须委托给工厂的工作来自己初始化所有这些参数...... 关于使用Client creator
作为工厂方法参数的方法 - 通过接口进行抽象Client
,这样如果通过注入Creator mock来测试这个工厂会很容易,并且工厂将非常灵活好。
要点: