使用工厂模式 [英] Use of factory pattern

查看:113
本文介绍了使用工厂模式的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

哪种方式使用厂是更好的(正确的)?

  IPacket信息= PacketFactory.CreatePacketObject(PacketType.Info,的currentUser,DateTime.Now,断开连接);
 

或者我应该扔出去第二种方法PacketFactory和使用这一个?

  IPacket信息= PacketFactory.CreatePacketObject(PacketType.Info);
            info.CreationTime = DateTime.Now;
            info.Creator =的currentUser;
            info.Data =断开连接;
 

或者一些其他的?

PacketFactory code:

 公共静态类PacketFactory
    {
        公共静态IPacket CreatePacketObject(PacketType型)
        {
            IPacket packetToCreate = NULL;
            开关(类型)
            {
                案例PacketType.Info:
                    packetToCreate =新信息();
                    打破;
                案例PacketType.Log:
                    packetToCreate =新记录();
                    打破;
                案例PacketType.Message:
                    packetToCreate =新信息();
                    打破;
            }
            返回packetToCreate;
        }

        公共静态IPacket CreatePacketObject(PacketType类型,客户端生成器,日期时间CREATIONTIME,字符串数据)
        {
            IPacket packetToCreate = NULL;
            开关(类型)
            {
                案例PacketType.Info:
                    packetToCreate =新的信息(创建者,CREATIONTIME,数据);
                    打破;
                案例PacketType.Log:
                    packetToCreate =新日志(创建者,CREATIONTIME,数据);
                    打破;
                案例PacketType.Message:
                    packetToCreate =新的消息(创造者,CREATIONTIME,数据);
                    打破;
            }
            返回packetToCreate;
        }

    }
 

解决方案

在应用模式,你应该有你获得这样做有什么明确的想法,在这种情况下我实在不明白,引入静态工厂正在获得你任​​何东西。但从客户端的角度看它 PacketFactory :已引进它减少了客户端和各种具体实现者之间的耦合 IPacket ?我认为不会,因为客户机已经知道它想通过指定 PacketType.Info IPacket 的$ C>, PacketType.Message PacketType.Log 。这是怎么回事什么不同客户了解有关信息消息登录班?由于工厂是一个静态类的客户端一样连接到类型 IPacket 返回因为这将是,如果它只是调用适当的构造函数 IPacket 执行者,因为你将不得不更改客户端,以便它在这两种情况下不同类型的 IPacket 的工作。

所以,如果你真的必须使用某种类型的工厂,那么我会建议使用抽象工厂模式,使本厂的客户只能依赖于工厂接口上,因此将能够与不同类型的工作 IPacket ,而无需改变。例如:

 公共接口IPacketFactory
{
   IPacket CreatePacket();
   IPacket CreatePacket(客户创造者,日期时间CREATIONTIME,字符串数据);
}

公共类的MessageFactory:IPacketFactory
{
   公共CreatePacket()
   {
      返回新的消息();
   }

   公共CreatePacket(客户创造者,日期时间CREATIONTIME,字符串数据)
   {
      返回新的消息(创造者,CREATIONTIME,数据);
   }
}

//你会实现工厂的每个IPacket类型...

公共类客户端
{
   私人IPacketFactory _factory;

   公共客户端(IPacketFactory厂)
   {
      _factory =工厂;
   }

   公共SomeMethodThatNeedsToCreateIPacketInstance()
   {
      IPacket包= _factory.CreatePacket();

     //与包工作,而无需关心它是什么类型
   }

}


//更高级别类或IOC容器将构建客户端,与相应的工厂

Client客户端=新的客户端(新的MessageFactory());

//客户端类可以用不同的IPacket情况下工作,没有它不必改变(它的去耦)

客户端客户端2 =新客户(新的LogFactory());
 

至于厂家是否应该允许人们构建一个 IPacket 没有指定的创造者,数据和创建时间或不依赖于类的不变量。如果类不变量可以满意没有指定的字段时,那么这很好,否则应符合规定。一类的工作的一部分应,以确保它不能被处于无效状态,因为类的用户将根据其是这样构成的。

在那里的 IPacket 实施者人需要额外的参数:

抽象工厂模式需要有是一个统一的界面,所有的实施者,因此,如果它是有道理的所有工厂有一个创建方法与额外的参数,那么你可以将它们添加到该接口。这方面的一个形式是通过一个对象的创建方法,可以用它来得到它需要额外的参数值不同的属性/方法。一个特殊的例子是双调度,其中调用者传递本身(在此情况下,客户端)并然后从该创建方法称为内

  //中的MessageFactory:在PacketContext包含各种数据可能与创造

公共IPacket创建(客户创造者,日期时间CREATIONTIME,字符串数据,PacketContext CTX)
{
   返回新的消息(创造者,CREATIONTIME,数据,ctx.SomeExtraData);
}

//中的LogFactory:日志并不需要从PacketContext什么,但它并调用一些在客户端(双调度)

公共IPacket创建(客户创造者,日期时间CREATIONTIME,字符串数据,PacketContext CTX)
{
   返回新日志(creator.Name,CREATIONTIME,数据);
}
 

您需要记住,我们的目标就是把抽象的类型 IPacket 被创建,因此如果同时执行这种方法,你开始得到的感觉是,客户端已开始暗中了解正在建设中,那么你可能要退一步,并考虑具体的类型,如果工厂是合适的。你唯一的选择是提供当你建造工厂的额外信息(即它传递给构造函数)。

 公共类的MessageFactory:IPacketFactory
{
   私有对象_data;

   公众的MessageFactory(对象而额外)
   {
      _data =而额外;
   }

    IPacket CreatePacket(客户创造者,日期时间CREATIONTIME,字符串数据)
    {
       返回新的消息(创造者,CREATIONTIME,数据,_extraData);
    }

    ///落实休息
}
 

这些重新present一些选项,但在任何情况下,我会强烈建议您不要使用静态或单工厂类,因为它会强夫妇您的客户端类的工厂,最可能是 IPacket 的子类。

Which way use of Factory is better(correct)?

IPacket info = PacketFactory.CreatePacketObject(PacketType.Info, currentUser, DateTime.Now, " disconnected");

or should I throw out second method in PacketFactory and use this one?

IPacket info = PacketFactory.CreatePacketObject(PacketType.Info);
            info.CreationTime = DateTime.Now;
            info.Creator = currentUser;
            info.Data = " disconnected";

or maybe some other?

PacketFactory code:

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;
        }

    }

解决方案

Before applying a pattern you should have a clear idea of what you gain by doing so, and in this instance I don't really see that introducing a static "Factory" is gaining you anything. Look at it from the point of view of the client of the PacketFactory: has introducing it reduced the coupling between the client and the various concrete implementors of IPacket? I would argue not since the client already has to know which kind of IPacket it wants by specifying a enumeration value of either PacketType.Info, PacketType.Message or PacketType.Log. How is that any different from the client knowing about the Info, Message and Log classes? Since the "Factory" is a static class the client is just as coupled to the type of IPacket being returned as it would be if it just called the constructor of the appropriate IPacket implementor because you would have to change the client in order for it to work with a different type of IPacket in either case.

So, if you really must use a Factory of some kind, then I would suggest employing the Abstract Factory pattern so that clients of the Factory would only depend on the factory interface and would therefore be able to work with different kinds of IPacket without having to change. For example:

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());

As far as whether the factory should allow one to construct an IPacket without specifying the creator, data and creation time or not depends on the class's invariants. If the class invariants can be satisfied when the fields are not specified then that's fine, otherwise they should be required. A part of a class's job should be to ensure that it cannot be constructed in an invalid state since users of the class will be depending upon that to be the case.

In the case where one of the IPacket implementors needs extra parameters:

The Abstract Factory pattern needs there to be a uniform interface for all implementers, so if it makes sense for all the factories to have a Create method with the extra parameters then you can add them to the interface. One form of this is to pass an object with various properties/methods that the Create method can use to derive the extra parameter values it needs. A special case is Double Dispatch where the caller passes itself (in this case the Client) and is then called from inside the Create method.

//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);
}

You need to remember that the goal is to abstract the type of IPacket being created, so if whilst implementing this approach you start to get the feeling that the Client is starting to implicitly know the specific type being constructed then you may have to take a step back and consider if the factory is appropriate at all. Your only other option is to provide the extra information when you construct the factory (i.e. pass it to the constructor).

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
}

Those represent some of the options, but in any case, I would strongly advise that you do not use a static or singleton "Factory" class because it will strongly-couple your client class to the factory and most likely the IPacket subclass.

这篇关于使用工厂模式的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆