学习 Policy based design - 读C++设计新思维-泛型编程与设计模式的应用
2013-12-23 00:32
1706 查看
现在将今年读过的一些书, 感觉比较有心得的地方做一些分享.
久闻Andrei, Alexandrescu的Modern C++ Design - Generic Programing and Design Patterns Applied是一本比较难的书,今年将其读了一遍, 确实如此, 大家如果要卒读的话,还是有一些建议:
1) 个人感觉最有用, 最核心的思想是前3章 - 基于Policy的Class 设计, 一些技术Techniques, 以及Type lists, 其中Policy based design尤为重要,可以精读理解.
2) 第4-第11章是作者以自己的思想重新实现常见的设计模式. 个人感觉现代C++的库(Boost及其他库) 有更简洁和更常用的方式,可以粗读了解一下.
3) 如果你工作在一些大型的,注重设计的C++ Code base上, 还是不妨细读一下全书大部分章节,比如Visitors, Multimethods, 因为往往可以碰见以模板, policy实作的程序框架, 可以在扩展和修改代码的时候心里更有底.
下面来讲一讲Policy based design, 其实这个东西是多继承和模板优点的集合体. 注意到以下几点问题:
1) 多重继承可以帮助处理设计组合, 但有一些问题: 基类没有足够派生类的类型信息, 如果要操作相同的状态, 那么这个状态必须被一个虚基类持有,并由子类们虚拟继承. 修改状态就是修改基类细节, 复杂, 没有弹性.
2) 模板无法特化数据成员, 也无法对多个模板参数的模板类的成员函数进行部分特化.
3) 多继承缺乏类型信息, 模板有的是信息, 模板难于扩张(特化) ,多继承很容易扩张. 多继承的继承结构难于套用, 模板很容易被套用.
那么, 组合这两个东西, 就得到了一套类似于Strategy设计模式的,在编译期作用的技术.
1) 在设计的时候, 逐步将Class里的Policies分离出来, 支持"可扩充的行为", 和"优雅的机能削减".
2) 设计一簇小Policies类的时候,尽量让Policies彼此间正交, 解除彼此的依赖.
给出一个例子来说明Policy建模的威力:
需求:我们来做一个手机跑分和信息软件:
1) 支持查询主流手机的部件信息: CPU, 内存, 显示屏, 电池.
2) 支持对手机进行Benchmark, 实际是对其子部件运行一些程序进行Benchmark.
3) 能修改某个手机的部件(改款), 也很容易快速加入新的手机进行Benchmark.
先对CPU,制作出一些类, 每个类中自己实现自己的Benchmark:
接下来实作出屏幕,电池部分:
有了这个智能手机模板,我们就开始生产2013年的风云手机吧, 暂时拿iPhone5, 小米红米手机, Samsung Galaxy Note3来做例子:(在我心中,小米是可以与苹果三星一战的哦)
练习:也可以给不同的产品加上其他有趣的Policies:
1) 在某些设计严格的代码中, 利用Policies可以减少代码,简化设计.比如现有的代码库中有一套接口整齐的Container Policies, 支持类似std::vector, std::list的常用操作. 当你需要用std::set的行为实现这些接口时,可以考虑针对Container写ArrayExtactor, ListExtractor, SetExtractor这样的policies, 避免生成新的container类.
2) 在写一些模板库的时候, 使用policies建模时被证明过有效的技术, 缺点是写这些代码也许不容易,但是使用这些代码的客户程序员一定会很爽.
结束语: Policies是一种模板技术,综合了模板和多继承的优点, 在编写库代码的时候特别有用, 谢谢! 我们下次见.
久闻Andrei, Alexandrescu的Modern C++ Design - Generic Programing and Design Patterns Applied是一本比较难的书,今年将其读了一遍, 确实如此, 大家如果要卒读的话,还是有一些建议:
1) 个人感觉最有用, 最核心的思想是前3章 - 基于Policy的Class 设计, 一些技术Techniques, 以及Type lists, 其中Policy based design尤为重要,可以精读理解.
2) 第4-第11章是作者以自己的思想重新实现常见的设计模式. 个人感觉现代C++的库(Boost及其他库) 有更简洁和更常用的方式,可以粗读了解一下.
3) 如果你工作在一些大型的,注重设计的C++ Code base上, 还是不妨细读一下全书大部分章节,比如Visitors, Multimethods, 因为往往可以碰见以模板, policy实作的程序框架, 可以在扩展和修改代码的时候心里更有底.
下面来讲一讲Policy based design, 其实这个东西是多继承和模板优点的集合体. 注意到以下几点问题:
1) 多重继承可以帮助处理设计组合, 但有一些问题: 基类没有足够派生类的类型信息, 如果要操作相同的状态, 那么这个状态必须被一个虚基类持有,并由子类们虚拟继承. 修改状态就是修改基类细节, 复杂, 没有弹性.
2) 模板无法特化数据成员, 也无法对多个模板参数的模板类的成员函数进行部分特化.
3) 多继承缺乏类型信息, 模板有的是信息, 模板难于扩张(特化) ,多继承很容易扩张. 多继承的继承结构难于套用, 模板很容易被套用.
那么, 组合这两个东西, 就得到了一套类似于Strategy设计模式的,在编译期作用的技术.
template < class RunPolicy, class FlyPolicy > class Bird : public RunPolicy, public FlyPolicy { }; class BirdOO : public IRunnable, public IFlyable { };简单是吧, Bird就是Policy的Host, 要想发挥policies的威力, 应该注意:
1) 在设计的时候, 逐步将Class里的Policies分离出来, 支持"可扩充的行为", 和"优雅的机能削减".
2) 设计一簇小Policies类的时候,尽量让Policies彼此间正交, 解除彼此的依赖.
给出一个例子来说明Policy建模的威力:
需求:我们来做一个手机跑分和信息软件:
1) 支持查询主流手机的部件信息: CPU, 内存, 显示屏, 电池.
2) 支持对手机进行Benchmark, 实际是对其子部件运行一些程序进行Benchmark.
3) 能修改某个手机的部件(改款), 也很容易快速加入新的手机进行Benchmark.
先对CPU,制作出一些类, 每个类中自己实现自己的Benchmark:
struct MTK6589 { static void BenchMark_4Core() { std::cout << "MTK 6589 Score : 12000" << std::endl; } }; struct SnapDragonS800 { static void BenchMark_4Core() { std::cout << "Snap dragon s800 Score : 22000" << std::endl; } }; struct A6 { static void BenchMark_2Core() { std::cout << "Apple A6 Score : 20000" << std::endl; } };
接下来实作出屏幕,电池部分:
struct HD { static void Display() { std::cout << "1280x720" << std::endl; } }; struct FHD { static void Display() { std::cout << "1920x1080" << std::endl; } }; struct AppleRetina { static void Display() { std::cout << "1136x640" << std::endl; } };
struct ReplacableBattery { static void Switch() { std::cout << "Switch the battery" << std::endl; } }; struct FixedBattery { };为了组装我们的智能手机, 我们来实作一些Policy类, 双核, 四核, 单核 处理器, OLED, LCD屏幕, 可更换/不可更换的电池策略:
template <class CPU> struct QuadCorePolicy { void BenchMark() { CPU::BenchMark_4Core(); } }; template <class CPU> struct DuelCorePolicy { void BenchMark() { CPU::BenchMark_2Core(); } }; template <class CPU> struct SingleCorePolicy { void BenchMark() { CPU::BenchMark_1Core(); } };
template <class DISPLAY> struct OLEDDisplayPolicy { void DisplayOLED() { DISPLAY::Display(); //write your oled code here } }; template <class DISPLAY> struct LCDDisplayPolicy { void DisplayLCD() { DISPLAY::Display(); //write your lcd code here } };
template <class BATTERY> struct ReplacableBatteryPolicy { void SwitchBattery() { BATTERY::Switch(); } }; template <class BATTERY> struct FixedBatteryPolicy { };有了这些Policies, 我们可以实作出对应的Host, 就是我们的智能手机类:
template <class CPU, class DISPLAY, class BATTERY, template<class C> class NUMCorePolicy = QuadCorePolicy, template<class D> class DisplayPolicy = LCDDisplayPolicy, template<class B> class BatteryPolicy = ReplacableBatteryPolicy > class SmartPhone : public NUMCorePolicy<CPU> , public DisplayPolicy<DISPLAY> , public BatteryPolicy<BATTERY> { };看上去是复杂了些, SmartPhone类使用了3个子部件的模板参数, 3个Policies.
有了这个智能手机模板,我们就开始生产2013年的风云手机吧, 暂时拿iPhone5, 小米红米手机, Samsung Galaxy Note3来做例子:(在我心中,小米是可以与苹果三星一战的哦)
void producePhones() { typedef SmartPhone<A6, AppleRetina, FixedBattery, DuelCorePolicy, LCDDisplayPolicy > AppleIPhone5; AppleIPhone5 iphone5; iphone5.BenchMark(); iphone5.DisplayLCD(); //Iphone could switch a battery? //iphone5.SwitchBattery(); typedef SmartPhone<MTK6589, HD, ReplacableBattery, QuadCorePolicy, LCDDisplayPolicy > XiaomiRedMi; XiaomiRedMi redmi; redmi.BenchMark(); redmi.DisplayLCD(); //Oh, I am run off of my battery, need switch a battery. redmi.SwitchBattery(); //hello, I want to produce a Samsung Galaxy Note III, and supports its benchmark. typedef SmartPhone<SnapDragonS800, FHD, ReplacableBattery, QuadCorePolicy, OLEDDisplayPolicy > SamsungNote3; SamsungNote3 note3; note3.BenchMark(); note3.DisplayOLED(); note3.SwitchBattery(); }不能换电池的手机(iPhone5), 编译器能帮你检查是否有Policy误用了哦.有了这些Policies类,我们就可以很灵活得实现一个类似手机数据库的东东, 虽然这些代码只是玩具.
练习:也可以给不同的产品加上其他有趣的Policies:
template <class CPU, class DISPLAY, class BATTERY> struct ApplePricePolicy { double price() { return 1.8 * (CPU::price() + DISPLAY::price() + BATTERY::price()); } }; template <class CPU, class DISPLAY, class BATTERY> struct XiaomiPricePolicy { double price() { return 1.3 * (CPU::price() + DISPLAY::price() + BATTERY::price()); } };玩了这些Policies, 那么我们在具体工程中有什么场景可以利用Policies呢?
1) 在某些设计严格的代码中, 利用Policies可以减少代码,简化设计.比如现有的代码库中有一套接口整齐的Container Policies, 支持类似std::vector, std::list的常用操作. 当你需要用std::set的行为实现这些接口时,可以考虑针对Container写ArrayExtactor, ListExtractor, SetExtractor这样的policies, 避免生成新的container类.
2) 在写一些模板库的时候, 使用policies建模时被证明过有效的技术, 缺点是写这些代码也许不容易,但是使用这些代码的客户程序员一定会很爽.
结束语: Policies是一种模板技术,综合了模板和多继承的优点, 在编写库代码的时候特别有用, 谢谢! 我们下次见.
相关文章推荐
- 读-《c++设计新思维-泛型编程与设计模式之应用》经典记录(英文书名:《modern c++ design》)
- 读-《c++设计新思维-泛型编程与设计模式之应用》经典记录(英文书名:《modern c++ design》)
- 学习C++设计新思维(泛型编程与设计模式之应用).pdf之继承关系检查
- 《C++设计新思维——泛型编程与设计模式之应用》读后感
- Modern C++ Design 学习笔记之Policy Based Class Design
- 设计模式学习—业务代表模式(Business Delegate Design Pattern)
- C#描述设计模式(2):工厂模式学习心得及我的项目应用
- 设计模式学习——策略模式:模拟鸭子应用
- 设计模式学习(1)——Design Pattern List
- 设计模式学习—组合实体模式(Composite Entity Design Pattern)
- 【嵌入式Linux学习七步曲之第七篇 Linux的高级应用编程】网络编程中并发服务器的设计模式
- JAVA学习--接口的应用:工厂方法的设计模式
- [转] 如何应用设计模式设计你的足球引擎(三和四)----Design Football Game(Part III and IV)
- 设计模式学习—拦截过滤器模式(Intercepting Filter Design Pattern)
- 设计模式-学习与应用
- 设计模式学习—状态模式(State Design Pattern)
- 设计模式学习总结系列应用实例
- 设计模式学习—代理模式(Proxy Design Pattern)
- [设计模式]--Design Patterns Explained学习笔记[chap4]
- [设计模式]--Design Patterns Explained学习笔记[chap1]