直觉地用计算机的方式去思考是初学者常见的问题
活字印刷
可维护:只更改需要更改的字
可复用:在后来的印刷中重复使用
可扩展:另外加字
高灵活:排版方式不同
使用封装、继承、多态,降低程序耦合。
业务封装
将业务和界面分离:Web、Windows、Linux平台下的计算机均可使用Operation
类。只需重写界面即可。
松耦合
构建一个基类Operation
,其他运算继承此基类,并重写其虚方法。如此可更容易地添加新运算。
简单工厂模式
用一个单独的类来进行创造实例的活动 。
1 2 3 4 oper = OperationFactory.create_pperate('+' ) oper.num1 = 1 oper.num2 = 1 result = oper.get_result()
如果需要修改加法,只需修正class OperationAdd
,增加其他运算只需添加对应的子类并修改工厂。
UML简介
接口实现:棒棒糖表示法
关联:一个类"知晓"另一个类,可用实线箭头表示
聚合:一种"弱拥有",A可包含B对象,但B对象不是A对象的一部分(如雁群与大雁),用空菱形(集体)箭头(个体)
合成:强拥有关系,严格的部分与整体(如鸟与翅膀)
依赖:虚线箭头表示,如动物与氧气
Design Pattern Guru
工厂模式的核心在于,"工厂"不单单只是一个制造"产品"的类,而是包含了大量业务逻辑的类。对工厂而言,产品总是实现相同的接口,并且业务逻辑相似。比如对于卡车和船两类产品而言,它们的"用法"都是相同的,都需要载人、启动、运输、停止、下人这四个步骤。因此只需要在产品内实现这些步骤的具体细节就可以了。如果想创造一个新交通工具,只需要重写这四个方法,就能无缝运行。
换言之,业务逻辑在工厂,而产品实现每个步骤的具体细节。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 #include <functional> #include <iostream> #include <stdexcept> class Dialog { public : Dialog () : btnOk (createButton ()) {} virtual ~Dialog () {delete btnOk;} virtual Button* createButton () const = 0 ; virtual void render () { btnOk -> onClick ([](){ std::cout << "Button clicked!" << std::endl; }); btnOk -> render (); } private : Button* btnOk; }; class WindowsDialog : public Dialog { public : Button* createButton () const override { return new WindowsButton (); } }; class WebDialog : public Dialog { public : Button* createButton () const override { return new WebButton (); } }; class Button { public : virtual void onClick (std::function<void ()> callback) const = 0 ; virtual void render () const = 0 ; }; class WindowsButton : public Button { public : void onClick (std::function<void ()> callback) const { } void render () const { } }; class WebButton : public Button { public : void onClick (std::function<void ()> callback) const { } void render () const { } }; class Application { public : Application () dialog (nullptr ) { Config config = readConfigFile (); if (config.OS == "Win" ) dialog = new WindowsDialog (); else if (config.OS == "Web" ) dialog = new WebDialog (); else throw std::runtime_error ("invalid config.OS" ); } ~Application () {delete dialog;} void run () { if (dialog) dialog -> render (); } private : Dialog* dialog; };
C++这种静态类型语言的多态与Python这种动态类型有重要差异:对C++而言,多态是依靠某一个共同的基类实现的,例如基类Base同时被A和B类继承。某一个函数若想同时处理AB两类,就需要把函数声明为ReturnType func(Base& abClass)
。但对于Python而言,可以直接写成def func(ab_class)
。Python的这种行为更加隐式、自然。所谓_Duck type_,是指如果一个对象实现了所需的方法或属性,那么它就可以被用在任何期望这些方法或属性的地方,而不管它的实际类型是什么。
此外虚函数是C++多态的重要实现部分。由于多态必须通过基类实现,因此对于重写的虚函数,即使使用基类指针或引用,调用的也是重写版本。非虚方法也可以重写,但是无法体现多态。使用基类指针或引用调用方法时,指向的是重写前的缺省方法。这可能导致非预期的结果。