![](https://p-blog.csdn.net/images/p_blog_csdn_net/Jinhao/456037/t_star.gif)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/Jinhao/456037/t_star.gif)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/Jinhao/456037/t_star.gif)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/Jinhao/456037/t_star.gif)
![](https://p-blog.csdn.net/images/p_blog_csdn_net/Jinhao/456037/t_star.gif)
rel="File-List" href="file:///C:%5CUsers%5CADMINI%7E1%5CAppData%5CLocal%5CTemp%5Cmsohtml1%5C01%5Cclip_filelist.xml">
现代程序开发最关注的一件事之一就是如何提高代码的可复用性和可维护性。
OOP提供了抽象概念来构建一个统一的世界模型,具像的物理对象被实现在这个简单的抽象模型体系中,最终形成庞大的树型结构来覆盖由该抽象涉及到的方方面面,可复用性由此诞生。
GP提供了另类的复用方法,让算法与类型无关。
在大多数的开发中,GP的运用几乎为空白,其实这并不是坏现象,除了让部分代码变得稍微优雅,剩下的可以说在大部分情况下,GP都是画蛇添足。在开发中, 我们努力用OO的知识和经验来创建类,让这些类对象相互协同工作来达到目的,一般情况下,我们是处在一个很小的问题域中着手解决具体的问题,不需要更多的 思考,所以template关键字几乎可以不用出现在我们编写的代码当中。
在以往的观点中,GP和OOP就像两条平行线,一边是静态多态,一边是动态多态,这样的观点让很多人误解了GP,加上在实际工作中,几乎不写template关键字,从而加深了这种误解。
到底GP存在的意义在哪里?相信大多数C++程序员都会用到STL,正是GP造就了STL的应用如此广泛。GP是一种用来开发高效,高复用程序库的编程范式,所以在实际工作的大多数项目中,GP对我们来说可有可无。用GP来分析问题的三个步骤:
1,将抽象问题域分类成Concepts.
在STL中,迭代器按行为被分类成5类。Input/Output/Forward/Bidirectional/Random Access Iterator。
2,基于这些Concepts,设计泛型算法。
例如std::generate要求Forward Iterator,而std::next_perutation要求Bidirectional Iterator.
3, 创建Concepts的具体模型。
例如,std::vector的Iterator,std::map的Iterator。
其实GP的分析方式与OOP极其类似,都是由具体的事物寻找抽象,然后按抽象来设计,最后基于抽象实现具象。
那GP编写的泛型程序库到底好在哪里?
可复用性:
我们尝试用OO来实现vector
- class oo_vector
- {
- public:
- void push_back(vec_elem_t& r)
- {
- vec_elem_t * n = r.clone(*this);
- //hold n ...
- }
- };
如果我们要使用 oo_vector ,那么存储的元素类型必须由 vec_elem_t 派生并实现 clone 方法。如果用 C++ Templates 来实现,复杂度自然降低。至少我们的元素类型不会出现派生自 vec_elem_t, map_elem_t, list_elem_t 等等这种庞大的多重继承的情况。
粘和性:
用上面的 oo_vector 来思考。如果有一个现成的类,要让 oo_vector 来操作,该怎么办? C++ Templates 应用到这种情况下大大提高了粘和性和可复用性。
Templates 把C++变得太“泛”了?
C++ 是强类型语言,继承确定了两个类的关系,这种关系可以某些方法作用于子类对象上,他们之间存在着一种限制。而对于一个泛型算法,它能接纳的模板参数 T ,从形式上,看不到任何限制,但这也许会使你的代码编译失败。例如把 std::list 的 iterator 传递到 std::find 中,得到的编译错误是 iterator 缺少某某东西,在这种情况下,如果编译错误能提示 list 的 iterator 不能用在 find 里,这样就会友好很多。其实这不仅仅只是提示得友好,因为我们在设计这种泛型算法的时候就是依据上面提到的 Concepts ,这种 Concepts 在目前的 C++ 语言中,只是一个潜在限制,作为泛型库的使用者,很容易忽略掉这种限制。或许有人会认为,如果 C++ 引入 Concepts 的限制来做类型的检查,那么它还会是 GP 吗?它仍然是 GP ,显而易见的,泛型库的设计是从 Concepts 出发,这好比一个子类是从基类出发一样。
Concepts 会是画蛇添足吗?
就算语言引入了 Concepts ,那么 list 的 iterator 仍然不能用到 find 中去,这和没有 Concepts 的情况完全一样。 Concepts 描述了一组抽象的行为,我们可以提供一个算法函数来处理具有这种行为的类型,它的引入会把人们的关注目光从围绕 T 上转移到 Concept 上,这能更好地表达每个抽象的核心思想。按 Concepts 来特化算法,比按类型来特化算法是更好 G P ,因为GP原本就与类型无关 。在解决 list::iterator 应用到 find 的问题上,只需要特化一个符合 list::iterator Concept 的 find 即可。
现在看来 GP 和 OOP 似乎很相似了,从分析的角度来说,他们的方向是一样,只是方法不同。这两个范式的区别不像 OOP 和面向过程那样,立竿见影。或许说, GP 和 OOP 都应该是一种 “ 泛型 ” , GP 是基于行为概念的抽象, OOP 则是基于事物概念的抽象。在 OO 的设计中,我们仍然会考虑到行为这一问题,只不过从 OO 的角度来说,这太隐晦,而 GP 在这方面则表达得更好,更抽象。