提高可读性和可维护性:省略许多变量声明的< >可能吗?
Increase readability & maintainability : omit < > for many variable declaration possible?
这个问题看起来很抽象。我将举个例子来问。
引言
假设我有许多类型的游戏对象。
它们是子弹,火箭,敌人,区域。
它们都是精心制作的&已删除&由池管理,例如
Pool<Bullet> poolBullet ;
Pool<Rocket> poolRocket ;
游戏逻辑将以Pool_Handle<xxx>,例如
Pool_Handle< Bullet > bullet = poolBullet.create() ;
Pool_Handle< Rocket> rocket = poolRocket .create() ;
问题
现在,我来看看重构。
例如,如果我的旧代码是。。。
Bullet* functionA(Rocket* rocket){
for(int n=0;n<rocket->zones.size();n++){
Zone* zone = rocket->zones.get(n);
Bullet* return_value =zone.functionB();
}
}
它会变成。。。
Pool_Handle<Bullet> functionA(Pool_Handle<Rocket> rocket){
for(int n=0;n<rocket->zones.size();n++){
Pool_Handle<Zone> zone = rocket->zones.get(n);
Pool_Handle<Bullet> return_value =zone.functionB();
}
}
请注意,它们现在到处都是Pool_Handle。
在阅读和编辑了这数千行代码几天后,我已经习惯了Pool_Handle,甚至比任何游戏对象都更习惯。这可能是我现在打字最快的一个词。
问题
如何将可读性和可维护性保持在旧代码的同等水平,如果可能的话,如何减少变量模板的键入时间?
我不希望有一个完美的答案,因为我找到的每一个解决方案都有一些权衡。
我糟糕的解决方案
/** remedy 1 **/
template <class TT> using H = Pool_Handle<TT>; //remedy line
H<Bullet> bullet ; //alleviate symptom, better but not perfect
/** remedy 2 **/
using H_Bullet = Pool_Handle<H_Bullet>; //remedy line
H_Bullet bullet ; //looks good, but have limitations
/** remedy 3 **/
auto bullet; //concise, but can't be used everywhere, sometimes also reduce readability
第二种解决方案看起来不错,但引入了一些限制。
我必须为子弹、火箭。。。等等,一个接一个
如果有一个新类型的游戏对象,我将不得不手动添加另一行。
如果游戏对象被重命名,例如Bullet->MetalBullet,我还必须手动将补救行更改为H_MetalBullet。
因此,它降低了整体可维护性。
有更好的方法吗?
(编辑)你可以假设c++11,c++14,不管怎样
(编辑)独立于平台的解决方案是有利的。
编辑1(进一步澄清第二个解决方案不完美的原因)
在第二个解决方案中;另一个";声明一个新类之后的行。
线路是。。。
using H_Bullet = Pool_Handle<H_Bullet>;
我应该把它放在哪里?
内部Bullet.h;
这会造成不好的耦合,因为Bullet根本不应该知道手柄。
在每个游戏逻辑文件所包含的某个高级标头内;
结果是,有两个不同的地方对Bullet有一些定义
更多位置->可维护性较低。
这两个地方都会产生一些小缺点:当我调用一些自动重构时,我必须调用两次,分别是Bullet和H_Bullet
选项1
使用auto
说明符:
auto object = pool.create();
完整示例:
template <typename T>
class Pool {
public:
class Handle {};
Handle create () const {
return Handle();
}
};
class Object {};
int main () {
Pool<Object> pool;
auto object = pool.create();
}
查看成功编译结果
选项2
使用typedef
(对于那些无法访问c++11功能的用户):
Object::Handle object = pool.create();
完整示例:
template <typename T>
class Pool {
public:
class Handle {};
Handle create () const {
return Handle();
}
};
class Object {
public:
typedef Pool<Object>::Handle Handle;
};
int main () {
Pool<Object> pool;
Object::Handle object = pool.create();
}
查看成功编译结果
除了使用auto
,您还可以从使用STL算法而不是手工编写的循环中受益。在您的示例中,而不是
Pool_Handle<Bullet> functionA(Pool_Handle<Rocket> rocket){
for(int n=0;n<rocket->zones.size();n++){
Pool_Handle<Zone> zone = rocket->zones.get(n);
Pool_Handle<Bullet> return_value =zone.functionB();
}
}
你可以使用std::for_each
std::for_each( rocket->zones.begin(), rocket->zones.end(),
[](auto const& z) {z.functionB();} );
对于这种简单的情况,每个循环的C++11可能更好:
for(auto const& z: rocket->zones) {
z.functionB();
}
一般来说,我强烈建议查看范围库,例如Boost.range或Eric Niebler的range-v3。这使您能够编写非常精简但具有描述性的代码,例如
// call functionB on all zones and sum the results
auto sumOfResult = accumulate( rocket->zones | transformed( [](auto const& z) { return functionB(z);}) );
只向前声明您感兴趣的类型的头有什么问题?只有当您向系统中添加需要句柄的新类型时,它才会发生变化,如果您重命名/添加某些内容,它就会正常中断。
types_fwd.hpp
template <typename> Pool;
template <typename> Pool_Handle;
class Bullet;
class Rocket;
using H_Bullet = Pool_Handle<Bullet>;
using H_Rocket = Pool_Handle<Rocket>;
唯一的另一种选择是反转并转发声明池和句柄,并将其包含/添加到引入需要句柄的新类型的每个头中。
- 请解释这句话(cout<<1+int((a<b)^((b-a)&1) )<<endl
- 呼叫运营商<<临时
- 如何防止clang格式在流运算符调用之间添加换行符<<
- <<操作员在下面的行中工作
- EASTL矢量<向量<int>>连续的
- C - 创建矢量&lt; vector&lt; double&gt;&gt;矩阵具有分配而不是inizializ
- 为什么将此对向量&lt; map&lt; int,int&gt;&gt;中的地图进行更新.失败
- C :对矢量进行排序&lt; struct&gt;(结构有2个整数)基于结构的整数之一
- 明确的专业化“ CheckIntmap&lt;&gt;”实例化
- 什么是模板&lt;&gt;inline bla bla
- 编辑C Qlist&lt; object*&gt; gt;QML代码和一些QML警告中的模型
- eigen :: llt&lt;eigen :: matrixxd&gt;具有不完整的类型
- 错误,包括&lt; ctype&gt;在原子上使用C 11
- std::vector<;uint8_t>;当C++11/14启用时,手动复制而不是调用memcpy
- 如何加入向量&lt; int&gt;到C 中的单个INT
- 是std :: set&lt; std :: future&gt;不可能存在
- 是numeric_limits&lt; int&gt; :: is_modulo从逻辑上矛盾
- opencv 2.4.7在iOS错误背景_segm.hpp #include&lt; list&gt;未找到
- 在修改列表后,std :: list&lt; t&gt; :: end()的值是否会更改
- ///<评论></评论>在Visual Studio中