使用设计模式优化设计案例<一>
2016-02-23 21:27
573 查看
首先看一种简单的实现打印二叉表达式树
简单的实现: 使用switch 语句,分类实现
这种设计的缺点:
几乎没有使用封装;
节点和边的耦合性比较高;
算法的复杂性比数据结构的复杂度要高很多,算法处理的绝大部分的工作;
由于没有封装,可扩展性必然较差;
采用面向对象的方法:
识别的类:
class Node:
class Int_Node:
class Unary_Node:
class Binary_Node:
class Tree:
C++ Node Interface: 定义print 打印 纯虚函数
C++ Tree Interface: 这里定义了一个 符号重载函数,用于树的打印
C++ Int_Node Implementation
用工厂模式改进:集中初始化,方便应对变化
1. 有不同的子类型,需要集中初始化
2. 使得改变添加新的Node 变的简单
使用工厂模式,构建Tree 的子模型
打印子树(Printing Subtrees)
在打印子树的时候,我们并不需要关心树中节点的类型,以及他们的继承关系。使用桥接器模式可以很好的做到这点
桥接器模式:
提供统一的即封闭又开放的接口: 接口不允许被修改,接口允许扩展
适配器: 把类的接口转换为另外的接口
适配器模式关心解决的问题:
1. 适配器模式允许不同类不因为接口不兼容而不可共同工作。
Using Adapter Pattern
C++ Main Program
使用面向对象方法也有一些潜在的问题:
解决方案通常 数据结构 部分很臃肿, 需要包含各种cpp 文件 .h 文件
可能不如最原始的方案来的效率高, 因为包含有虚拟函数,增加了开销
关键code源码赏析: Tree.cpp
Project download:
Here
简单的实现: 使用switch 语句,分类实现
void print_tree(Tree_Node *root){ switch(root > tag_){ case NUM: printf("%d", toot->num_); break; case UNARY: printf("%s",root->op_[0]); print_tree(root->unary_); printf(")"); break; case BINARY: print_tree(root_binary_l); print_tree(root_binary_r); break; default: printf("error, unknown type"); } }
typedef struct Tree_Node Tree_Node; struct Tree_Node{ enum{NUM, UNARY,BINARY} tag_; short use_; /*reference count*/ union{ char op_[2]; int num_; }o;
#define num_ o.num_ #define op_ o.op_ union{ Tree_Node *unary_; struct {Tree_Node *l_, *r_;} binary_; }c;
#define unary_ c.unary_; #define binary_ c.binary_ };
这种设计的缺点:
几乎没有使用封装;
节点和边的耦合性比较高;
算法的复杂性比数据结构的复杂度要高很多,算法处理的绝大部分的工作;
由于没有封装,可扩展性必然较差;
采用面向对象的方法:
识别的类:
class Node:
class Int_Node:
class Unary_Node:
class Binary_Node:
class Tree:
C++ Node Interface: 定义print 打印 纯虚函数
class Tree; class Node { friend class Tree; protected: Node():use (1){} //pure virtual void print(std::ostream&) const =0; public: int use; //reference counter. };
C++ Tree Interface: 这里定义了一个 符号重载函数,用于树的打印
class Tree { public: Tree(int); Tree(const string&, const Tree &); Tree(const string&, const Tree &,const Tree &); Tree(const Tree&t); void operator=(const Tree &t); ~Tree(); void print(std::ostream&) const; private: Node *node; // pointer to a rooted subtree }; std::ostream &operator<<(std::ostream &s, const Tree& tree);
C++ Int_Node Implementation
Int_Node::Int_Node(int k):num(k){} void Int_Node::print(std::ostream &stream)const{ stream<<this->num; }
用工厂模式改进:集中初始化,方便应对变化
1. 有不同的子类型,需要集中初始化
2. 使得改变添加新的Node 变的简单
使用工厂模式,构建Tree 的子模型
Tree::Tree(int num) : node_ (new Int_Node (num)) {}
Tree::Tree(const string&op, const Tree &t) :node_(new Unary_Node(op,t)) {}
Tree::Tree(const string &op, const Tree &t1, const Tree &t2) : node_ (new Binary_Node(op,t1,t2)){}
打印子树(Printing Subtrees)
在打印子树的时候,我们并不需要关心树中节点的类型,以及他们的继承关系。使用桥接器模式可以很好的做到这点
桥接器模式:
提供统一的即封闭又开放的接口: 接口不允许被修改,接口允许扩展
void Tree::print(std::ostream &os) const{ this->node->print(os); }
适配器: 把类的接口转换为另外的接口
适配器模式关心解决的问题:
1. 适配器模式允许不同类不因为接口不兼容而不可共同工作。
Using Adapter Pattern
std::ostrream &operator<<(std::ostream &s, const Tree &tree) { tree.print(s);// 得益于上面的桥接器模式实现 //this triggers Node *virtual all via tree.noe->print(s), which is implemented as the following: //(*tree.node_->vptr[1])(tree.node_,s); return s; }
C++ Main Program
#include<istd::ostream.h> #include "Tree.h" int main(int, char*[]){ const Tree t1 = Tree("*", Tree("-",5),Tree("+",3,4)); cout<<t1<<endl; // prints ((-5) * (3 + 4)) const Tree t2 = Tree("*",t1,t1); //prints (((-5)*(3+4))*((-5)*(3+4))) cout<<t2<<endl; return 0; // destructors of t1 ,t2 recursively }// delete entire tree when leaving soope
使用面向对象方法也有一些潜在的问题:
解决方案通常 数据结构 部分很臃肿, 需要包含各种cpp 文件 .h 文件
可能不如最原始的方案来的效率高, 因为包含有虚拟函数,增加了开销
关键code源码赏析: Tree.cpp
#include"Tree.h" #include"Int_Node.h" #include"Binary_Node.h" #include"Unary_Node.h" Tree::Tree(int num) :node(new Int_Node(num)){} Tree::Tree(const string &op,const Tree &t) :node(new Unary_Node(op,t)){} Tree::Tree(const string &op, const Tree &t1, const Tree &t2) :node(new Binary_Node(op,t1,t2)){} Tree::~Tree(){ --this->node->use; if(this->node->use <= 0) { delete this->node; } } void Tree::print(std::ostream&os) const { this->node->print(os); } Tree::Tree(const Tree&t):node(t.node){ ++this->node->use; //shareing,ref-counting; } void Tree::operator=(const Tree &t) { if(this == &t) return; ++t.node->use; --this->node->use; if(this->node->use == 0) delete this->node; this->node = t.node; } std::ostream &operator<<(std::ostream &s, const Tree& tree) { tree.print(s); //This triggers Node *virtural call via // tree.node -> print(s), which is implemented as the following //(*tree.mode->vptr[1]) (tree.node, s); return s; }
Project download:
Here
相关文章推荐
- 初探psutil
- Android Studio快捷键
- SringMvc 中操作 session 中的数据
- iOS百度地图API的使用
- 研究try catch finally return
- 并查集入门笔记
- 康托尔定理是如何证明的?
- ios不同版本下的UILabel自动换行问题
- 16年面试提问
- linux shell 字符串操作详解 (长度,读取,替换,截取,连接,对比,删除,位置 )
- 如何找出执行最慢的SQL
- 岁月划过生命线——大三下
- 【Linux学习016】facl与Linux终端
- 网络编程3---常用服务器编程模型
- 什么时候应该使用$scope.$apply()
- 独特的php遍历数组的写法,reset(),next(),current()
- 优秀的PHP开源项目集合
- 枚举变量
- 响应式布局基础一:px、dpi、ppi的区别
- MapReduce读取Hbase中多个版本的数据,统计例子。