正确实现依赖注入的一种方法是将对象创建与业务逻辑分开.通常,这涉及使用Factory进行对象创建.
到目前为止,我从未认真考虑过使用工厂,所以如果这个问题看起来有点简单,我会道歉:
在我遇到的工厂模式的所有示例中,我总是看到没有参数化的非常简单的示例.例如,这是一个工厂从Misko Hevery偷来的优秀如何思考"新"操作员文章.
class ApplicationBuilder {
House build() {
return new House(new Kitchen(
new Sink(),
new Dishwasher(),
new Refrigerator())
);
}
}
但是,如果我希望我建造的每个房子都有名字,会发生什么?如果我按如下方式重新编写此代码,我还在使用工厂模式吗?
class ApplicationBuilder {
House build( const std::string & house_name) {
return new House( house_name,
new Kitchen(new Sink(),
new Dishwasher(),
new Refrigerator())
);
}
}
请注意我的Factory方法调用已更改为:
ApplicationBuilder builder; House * my_house = builder.build();
对此:
ApplicationBuilder builder;
House * my_house = builder.build("Michaels-Treehouse");
顺便说一句:我认为将对象实例化与业务逻辑分离的概念很棒,我只想弄清楚如何将它应用于我自己的情况.令我困惑的是,我看到的Factory模式的所有示例都没有将任何参数传递给build()函数.
要清楚:在我需要实例化它之前,我不知道房子的名称.
比方说,我有一个抽象类饮料,以及选择的饮料(葡萄酒,啤酒等)的类型在运行时创建的工厂方法.
每个饮料都需要一些参数来正确初始化自己.其中一些是所有饮料的共同点; 例如,他们可能都需要DrinkConfig参数.
但每种饮料也可能有其独特的要求.也许Wine需要一个Sommelier辅助对象来初始化自己.啤酒不需要它,但它可能需要它自己的辅助对象.
那么我应该将什么传递给工厂方法呢?当我调用它时,我有所有可用的辅助对象,所以我可以将它们全部传递给工厂.但这最终可能会引发很多争论.有没有更好的方法来设计它?
编辑:我们假设我不能在工厂中创建辅助对象; 他们只能从来电者处获得.
我读了Jim Hyslop和Herb Sutter 的文章抽象工厂,模板风格.该工厂实现为Singleton.它们提供了一种使用RegisterInFactory助手类自动注册类的简便方法.
现在我已经多次阅读过Singletons应该避免的内容,有些人甚至将它们视为反模式,并且只有少数情况下它们是有用的.这是其中之一吗?或者是否有另一种方法可以提供自动批准类的简单方法?
这是导致错误的代码:
Factory.h:
#include <string>
#include <map>
namespace BaseSubsystems
{
template <class T>
class CFactory
{
protected:
typedef T (*FunctionPointer)();
typedef std::pair<std::string,FunctionPointer> TStringFunctionPointerPair;
typedef std::map<std::string,FunctionPointer> TFunctionPointerMap;
TFunctionPointerMap _table;
public:
CFactory () {}
virtual ~CFactory();
}; // class CFactory
template <class T>
inline CFactory<T>::~CFactory()
{
TFunctionPointerMap::const_iterator it = _table.begin();
TFunctionPointerMap::const_iterator it2;
while( it != _table.end() )
{
it2 = it;
it++;
_table.erase(it2);
}
} // ~CFactory
}
Run Code Online (Sandbox Code Playgroud)
我得到的错误:
error: no matching member function for call to 'erase' [3]
_table.erase(it2);
~~~~~~~^~~~~
Run Code Online (Sandbox Code Playgroud)
有小费吗?谢谢.
在使用工厂模式时,工厂应该包含验证逻辑还是应该留给调用类来处理传递上下文数据之前的验证?
我有一个简单的工厂方法,但它依赖于传递给它的配置树来决定要实例化的对象.
可能存在这样的情况:配置xml可能形成良好,但不是工厂期望的正确格式,我不知道应该在哪里验证.
在Zend Framework 2中使用工厂类或闭包更好吗?为什么?
我知道闭包不能被序列化,但如果你从Module#getServiceConfig()返回它们,这不会影响其余配置数据的缓存,并且闭包将被缓存在你的操作码缓存中.
在构建工厂类与执行闭包时,性能有何不同?PHP是否仅在执行时包装和实例化闭包,或者它是否会在每个请求中为配置文件中定义的每个闭包执行此操作?
有没有人比较过每种方法的执行时间?
也可以看看:
我知道有很多关于不同工厂模式的差异的问题,但答案是如此不同和令人困惑.我读过的书籍使用不清楚和(简化)简化的例子.即使在阅读维基百科的解释之后,我也有很多问题,以及关于它们的大量在线解释,包括所有这些网站上的解释.我正在阅读的这本书是Head First Design Patterns.
在Simple Factory中,客户端使用单独的类(Creator)和工厂方法(可以是静态的)来返回Products.
在工厂方法模式中,创建者和客户端是相同的东西,他们在同一个类中使用抽象方法来创建新的产品,它们在同一个类中运行.当然,造物主(或客户)是抽象的,因此关于制作混凝土产品的决定被推迟到子类.
我的理解是否正确(例如,FMP中的客户端和创建者是同一件事,我从未在FMP图中看到客户端)?
在Factory Method Pattern中,它表明create方法不能在Creator之外重用,所以它只能在创建一个新的Creator时重用?
在哪种情况下我可以选择一个而不是另一个?
(PS请不要将此标记为重复,我希望在此网站上明确这一点)
我正在尝试为派生类创建一个工厂.我只希望工厂能够创建派生类的实例,所以我已经创建了基础构造函数protected; 派生类只使用基类构造函数,因此它们的构造函数protected也是如此.
我试图将工厂声明为基类的朋友,以便它可以访问protected构造函数.当我使用此命令编译时
clang++ -std=c++11 -stdlib=libc++ Friends.cpp -o Friends
Run Code Online (Sandbox Code Playgroud)
我收到此错误:
Friends.cpp:23:20: error: calling a protected constructor of class 'A'
return new T(i);
^
Friends.cpp:42:16: note: in instantiation of function template specialization 'Create<A>' requested
here
A* a = Create<A>(1);
^
Friends.cpp:30:25: note: declared protected here
using Base::Base;
^
Run Code Online (Sandbox Code Playgroud)
与派生类的类似错误一起B.
我从stackoverflow.com上读到其他问题的感觉,这在C++ 11中是不可能的,但我不确定为什么.有人可以解释为什么这不起作用,或许可以替代?
示例代码
#include <iostream>
using namespace std;
// Forward declaration
template<class T> T* Create(int i);
class Base {
public:
template<class T>
friend T* …Run Code Online (Sandbox Code Playgroud) 在大多数任意应用中,需要在所有可用层中解决许多交叉问题,例如日志记录,消息总线,配置.我注意到的是,在某些类中,如果使用IoC注入模块,它们往往会完全炸毁构造函数.
public class MyService : IService
{
public MyService(ILogger logger, IAppSettings settings, IEventBus eventBus...)
{
}
}
Run Code Online (Sandbox Code Playgroud)
对于构造函数过度注入的常见情况,我倾向于将关注点折射成紧密组合在一起的构建块,因此我在类中获得的依赖项更少.但是,对于交叉切割概念,这是不可能的.
在日志框架中,静态工厂/服务似乎非常流行,例如
// Application root
MyLoggerService.SetFactory(log4NetFactory);
// Somewhere
MyLoggerService.GetLogger("name") // returns Log4NetLogger created by Log4NetFactory.
Run Code Online (Sandbox Code Playgroud)
我的问题是:对于各种交叉切割的东西,这种方法是否很好?如果代码最终看起来像这样,有什么缺点:
public class MyService : IService
{
private readonly IReallyNeedThat _dependency;
public MyService(IReallyNeedThat dependency)
{
_dependency = dependency;
}
private readonly ILogger _logger = LoggerService.GetLogger("MyService");
private readonly IEventBus _eventBus = EventBusService.GetEventBus();
private readonly IConfiguration _configuration = ConfigurationService.GetConfiguration(Level.Roaming)
private readonly IExceptionHandler _exceptionHandler = ExceptionPolicy.GetHandler();
private readonly ITracer _tracer = …Run Code Online (Sandbox Code Playgroud) c# design-patterns factory dependency-injection cross-cutting-concerns
现在我使用"Faker"公司名称进行单元测试失败.
看起来好像expect(response.body).to match(@thing.name)搞砸了.
在查看错误时,Faker公司的名称有时会包含"O'Brian Company"或"O'Hare Company"或类似名称.
faker是编码字符串吗?因为我知道匹配编码的字符串不是一个好主意,我真的不想只在Factory im中指定一个特定的公司名称.
谢谢