假设我有一个Employee_Storage包含数据库连接数据成员的对象.该数据成员是应该存储为指针还是作为引用?
如果我将它存储为参考,我不需要进行任何NULL
检查.(无论如何,NULL检查有多重要?)
如果我将它存储为指针,则更容易设置Employee_Storage
(或MockEmployee_Storage)以进行测试.
一般来说,我一直习惯于将我的数据成员存储为引用.但是,这使得我的模拟对象很难设置,因为NULL我现在必须传入true/mock对象,而不是传入s(大概是在默认构造函数中).
是否有一个很好的经验法则,特别是关注可测试性?
正确实现依赖注入的一种方法是将对象创建与业务逻辑分开.通常,这涉及使用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()函数.
要清楚:在我需要实例化它之前,我不知道房子的名称.
我最近安装了VsVim.
它很棒,但我发现自己不断触及鼠标以便在文件之间切换.
有内置的解决方案吗?我无法在任何地方找到VsVim快捷方式列表.
我在绘制协作图时试图让Doxygen忽略继承关系.
假设我的类定义如下所示:
class Derived : public Base
{
int x;
int y;
int z;
}
Run Code Online (Sandbox Code Playgroud)
现在,当我运行Doxygen时,我不希望在生成的协作图中看到Base类.
乍一看,似乎最干净的方法是EXCLUDE_SYMBOLS在我的Doxyfile中使用该指令.特别:
EXCLUDE_SYMBOLS = Base
Run Code Online (Sandbox Code Playgroud)
但是,我发现这不起作用:Base类仍然显示在Derived的协作图中.我已经在Doxygen 1.8.6和1.8.11使用Base通配符的不同排列(Base*,*as*等)上尝试过这种行为. Base类始终显示在我的协作图中.
公平地说,我找到了2个解决方法,但它们都涉及将条件语句放入我的代码中.为了完整起见,我将在这里包括:
第一种解决方法:
class Derived :
#ifndef DOXYGEN_SHOULD_SKIP_THIS
public Base
#endif /* DOXYGEN_SHOULD_SKIP_THIS */
{
...
}
Run Code Online (Sandbox Code Playgroud)
然后确保在Doxyfile中设置以下两个指令:
PREDEFINED = DOXYGEN_SHOULD_SKIP_THIS
ENABLE_PREPROCESSING = YES
Run Code Online (Sandbox Code Playgroud)
第二种解决方法:
class Derived :
/// @cond DOXYGEN_IGNORE
public Base
/// @endcond
{
...
}
Run Code Online (Sandbox Code Playgroud)
需要明确的是,这些变通办法确实使Doxygen忽略了继承关系,但我不希望不必要地污染我的代码库,特别是如果有更好/更清洁的方法来实现我的目标.
我的问题是 - 为什么EXCLUDE_SYMBOLS在绘制协作图时不会让Doxygen忽略我的Base类?
我的程序有两个线程:
在主线程内部,我偶尔需要对数据库进行读取.当发生这种情况时,性能并不重要,但正确性是.(在一个完美的世界里,我会从缓存中读取,而不是到数据库的往返 - 但为了讨论,我们把它放在一边.)
如何确保主线程看到正确/静止的数据库?
标准互斥锁将无法工作,因为我冒着让主线程在数据刷新到数据库之前获取互斥锁的风险.这将是一个很大的竞争条件.
我真正想要的是某种互斥体,只有在互斥锁被抓取并释放一次之后才能执行主线程.这样的事情存在吗?解决这个问题的最佳方法是什么?
更新:在做了一些额外的研究后,我可能会使用Boost的条件变量来解决这个问题.要么那么,要么只是咬紧牙关并缓存我的写作.感谢您的反馈!
我正在构建一个C++应用程序,并且我有几个实用程序对象,我的所有类都需要使用它们.这些是日志记录对象,全局状态对象,DAL对象等...
到目前为止,我已经将所有这些对象作为引用传递给我的类构造函数.
例如:
class Honda : public Car
{
public:
Honda ( const GlobalState & state,
const Log & logger,
const DAL & dal );
...
private:
const GlobalState & my_state;
const Log & my_logger;
const DAL & my_dal;
}
这很快就会变得乏味,因为每次我添加一个我所有类都需要访问的实用程序对象时,我都必须在各处更改构造函数.
我听说解决这个问题的正确方法是创建一个包含所有不同实用程序对象的结构,并将其传递给所有需要访问它的对象(作为参考).
这是处理这个问题的正确方法吗?谢谢!
更新:感谢大家的反馈.经过一些额外的研究,我决定继续使用依赖注入.
这是一个我从未真正理解过的内存分配问题.
void unleashMonkeyFish()
{
MonkeyFish * monkey_fish = new MonkeyFish();
std::string localname = "Wanda";
monkey_fish->setName(localname);
monkey_fish->go();
}
在上面的代码中,我在堆上创建了一个MonkeyFish对象,为它指定了一个名称,然后在世界上释放它.假设分配的内存的所有权已经转移到MonkeyFish对象本身 - 只有MonkeyFish本身将决定何时死亡并自行删除.
现在,当我在MonkeyFish类中定义"name"数据成员时,我可以选择以下之一:
std::string name; std::string & name;
当我在MonkeyFish类中定义setName()函数的原型时,我可以选择以下之一:
void setName( const std::string & parameter_name ); void setName( const std::string parameter_name );
我希望能够最小化字符串副本.事实上,如果可以的话,我想完全消除它们.所以,似乎我应该通过引用传递参数......对吗?
让我感到困惑的是,一旦unleashMonkeyFish()函数完成,我的localname变量似乎将超出范围.这是否意味着我强行要通过副本传递参数?或者我可以通过引用传递它并以某种方式"逃脱它"?
基本上,我想避免这些情况:
我应该使用什么原型和数据成员组合?
澄清:有几个答案建议使用static关键字来确保在unleashMonkeyFish()结束时不会自动解除分配内存.由于此应用程序的最终目标是释放N MonkeyFish(所有这些都必须具有唯一名称),因此这不是一个可行的选择.(是的,MonkeyFish - 变幻无常的生物 - 通常会在一天内改变他们的名字,有时会改变几次.)
编辑:Greg Hewgil指出将name变量存储为引用是非法的,因为它没有在构造函数中设置.我在问题中留下了错误,因为我认为我的错误(和格雷格的纠正)可能对第一次看到这个问题的人有用.
我一直在尝试遵循依赖注入的原则,但在阅读本文后,我知道我做错了什么.
这是我的情况:我的应用程序收到不同类型的物理邮件.所有传入的邮件都通过我的MailFunnel对象.
在它运行时,MailFunnel从外部接收不同类型的消息:Box,Postcard和Magazine.
每种邮件类型都需要以不同方式处理.例如,如果Box进来,我可能需要在交付之前记录重量.因此,我有BoxHandler,PostcardHandler和MagazineHandler对象.
每次有新消息进入我的时候MailFunnel,我都会实例化一个新的相应MailHandler对象.
例如:
class MailFunnel
{
void NewMailArrived( Mail mail )
{
switch (mail.type)
{
case BOX:
BoxHandler * bob = new BoxHandler(shreddingPolicy, maxWeightPolicy);
bob->get_to_work();
break;
case POSTCARD:
PostcardHandler * frank = new PostcardHandler(coolPicturePolicy);
frank->get_to_work();
break;
case MAGAZINE:
MagazineHandler * nancy = new MagazineHandler(censorPolicy);
nancy->get_to_work();
break;
}
}
private:
MaxWeightPolcy & maxWeightPolicy;
ShreddingPolicy & shreddingPolicy;
CoolPicturePolicy & … 假设我有这样一个类:
class MonkeyFish
{
MonkeyFish( GlobalObjectA & a, GlobalObjectB & b, GlobalObjectC & c);
private:
GlobalObjectA & m_a;
GlobalObjectB & m_b;
GlobalObjectC & m_c;
}
没有工厂,我需要执行以下操作才能实例化a MonkeyFish.
GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;
int main()
{
MonkeyFish * monkey_fish = new MonkeyFish(a, b, c);
monkey_fish->go();
}
另一方面,如果我有MonkeyFishFactory,似乎我必须这样做:
GlobalObjectA a;
GlobalObjectB b;
GlobalObjectC c;
int main()
{
MonkeyFishFactory mf_factory(a, b, c);
MonkeyFish * monkey_fish = mf_factory.buildMonkeyFish("Bob");
monkey_fish->go();
}
我还有全局对象.
即使MonkeyFishFactory本身在GlobalObjects内部创建(因此它们现在在MonkeyFishFactory而不是真正的全局内),似乎MonkeyFishFactory 本身仍然需要是一个全局对象,以便我可以随时访问它来创建一个MonkeyFish. …
我想创建一个包含许多变量的字符串:
std::string name1 = "Frank";
std::string name2 = "Joe";
std::string name3 = "Nancy";
std::string name4 = "Sherlock";
std::string sentence;
sentence = name1 + " and " + name2 + " sat down with " + name3;
sentence += " to play cards, while " + name4 + " played the violin.";
Run Code Online (Sandbox Code Playgroud)
这应该产生一个读取的句子
弗兰克和乔坐下来与南希打牌,而夏洛克则拉小提琴.
我的问题是:实现这一目标的最佳方法是什么?我担心不断使用+运算符是无效的.有没有更好的办法?