例子1:负载监视器,如何在一个程序中实现对这些不同条件的适应呢?

int main()
{
WindowDisplay display;
Monitor monitor(&display);
while(running())
{
monitor.getLoad();
monitor.getTotalMemory();
monitor.getUseMemory();
monitor.getNetworkLatency(); monitor.show();
sleep();
} } enum MonitorType {Win32,Win64,Ganglia}; MonitorType type = Ganglia; float Monitor::getLoad()
{
switch(type)
{
case Win32:
//get system load via win32 APIs
return load;
case Win64:
//get system load via Win64 APIs
return load;
case Ganglia:
//get system load via ganglia interface
return load;
}
}
改进:使用模板方法;
class Monitor
{
public:
virtual void getLoad() = ;
virtual void getTotalMemory() = ;
virtual void getUseMemory() = ;
virtual void getNetworkLatency() = ; Monitor(Display *display);
virtual ~Monitor();
void show();
protected:
float load,latency;
long totalMemory,usedMemory;
Display *m_display;
}; void Monitor::show()
{
m_display->show(load,totalMemory,usedMemory,latency);
} class MonitorImpl1:public Monitor
{
public:
void getLoad();
void getTotalMemory();
void getUsedMemory();
void getNetworkLatency();
}; void MonitorImpl1::getLoad()
{
//load = ...;
} void MonitorImpl1::getTotalMemory()
{
//totalMemory = ...;
} 存在问题:
如果几组函数接口的实现互相独立,分别有N,M,K种实现方法,那么,实现子类的个数将是N*M*K种,
这样方法无非不是最好的; 分析:
存在两种不同层面的变化,应该有所区分:
在实现层面上:对于每个功能,存在多种实现方法;
.相对于基类是可变的,每种变化对应于一个派生类
.这种变化表现在编译器,是一种相对静态的可变
在组织层面上:“大”类的功能由一系列子功能构成
·子功能之间是互相独立的,应当将这些子功能拆分到不同的“小”中
.组合是自由变化的,动态的,可变的,通过实现子功能的“小”类对象的组合来完成
.这种变化表现在运行期,是一种更加动态的可变;
隔离不同层面的“变”:
.静态的可变用继承;
.动态的可变用组合;
单一责任:
.单一责任原则
类的功能应该是内聚的,一个类只承担一项功能;
表现为:修改、派生一个类只应该有一个理由,只能够由单个变化因素引起;
.将多个不同的功能交由一个类来实现,违反了单一责任原则;
当一个功能需要变化时,不得不修改或者派生新的实现类;
把这两个层次的“变”分离开
剥离出新的接口
每个功能(算法)的实现定义为一个接口(称为策略)
与接口的不同实现组成一个策略类的体系;
把这两种层次的“变”分离开
用组合替代继承
用功能(算法)接口之间的组合来实现功能(算法)之间的组合
再看看问题:
剥离新的接口
由三个策略接口分别定义不同的功能,每个策略接口有一系列不同的实现;
用组合替代继承
Monitor类中保存一组“策略”接口类的实例,这些实例可以自由组合和动态
替换;
class LoadStrategy
{
public:
virtual float getLoad() = ;
}; class LoadStrategyImpl1:public LoadStrategy
{
public:
float getLoad()
{
//get load here...
return load;
}
}; class LoadStrategyImpl2: public LoadStrategy
{
public:
float getLoad()
{
//get load here...
return load;
}
}; class MemoryStrategy
{
public:
virtual long getTotal() = ;
virtual long getUsed() = ;
}; class MemoryStrategyImpl1:public MemoryStrategy
{
public:
long getTotal()
{
//get total memory here...
return total;
}
long getUsed()
{
//get used memory here...
return used;
}
}; class MemoryStrategyImpl2:public MemoryStrategy
{
//
} class Monitor
{
public:
Monitor(LoadStrategy *loadStrategy,MemoryStrategy *memStrategy,
LatencyStrategy *latencyStrategy,Display *display);
void getLoad();
void getTotalMemory();
void getUsedMemory();
void getNetworkLatency();
void show();
private:
LoadStrategy *m_loadStrategy;
MemoryStrategy *m_memStrategy;
LatencyStrategy *m_latencyStrategy;
float load,latency;
long totalMemory,usedMemory;
Display *m_display;
}; //
Monitor::Monitor(LoadStrategy *loadStrategy,MemoryStrategy *memStrategy
,LatencyStrategy *latencyStrategy,Display *display):
m_loadStrategy(loadStrategy),m_memStrategy(memStrategy),
m_latencyStrategy(latencyStrategy),m_display(display),
load(0.0),latency(0.0),totalMemory(),usedMemory()
{ } void Monitor::show()
{
m_display->show(load,totalMemory,usedMemory,latency);
} 代码实现:
void Monitor::getLoad()
{
load = m_loadStrategy->getLoad();
} void Monitor::getTotalMemory()
{
totalMemory = m_memStrategy->getTotal();
} void Monitor::getUsedMemory()
{
useMemory = m_memStrategy->getUsed();
} void Monitor::getNetworkLatency()
{
latency = m_latencyStrategy->getLatency();
} int main(int argc, char *argv[])
{
GangliaLoadStrategy loadStrategy;
WinMemoryStrategy memoryStrategy;
pingLatencyStrategy latencyStrategy; WindowsDisplay display;
Monitor monitor(&loadStrategy,&memoryStrategy,&latencyStrategy,&display);
while(running())
{
monitor.getLoad();
monitor.getTotalMemory();
monitor.getUsedMemory();
monitor.getNetworkLatency(); monitor.show();
sleep();
}
} //灵活性:运行期
class Monitor
{
public:
//...
void setLoadStrategy(LoadStrategy *loadStrategy);
void setMemoryStrategy(MemoryStrategy *memoryStrategy);
void setLatencyStrategy(LoadStrategy *latencyStrategy);
}; int main()
{
Monitor monitor(//);
//...
LoadStrategyImpl2 newLoadStrategy;
monitor.setLoadStrategy(&newLoadStrategy);
monitor.getLoad();
//...
} //委托与接口的进一步分解
//结果的显示
class Monitor
{
public:
//...
void show();
protected:
float load,latency;
long totalMemory,usedMemory;
Display* m_display;
}; void Monitor::show()
{
m_display->show(load,totalMemory,usedMemory,latency);
} 执行过程:
Monitor将“显示”的任务“委托”给了Display,由Display真正完成显示的工作;
委托模式:Delegation,Wrapper,Helper...
int mian()
{
//...
monitor.show();
//调用代码:
/*
void Monitor::show()
{
m_display->show(load,totalMemory,usedMemory,latency);
}
//区分是WindowDisplay还是ConsoleDisplay
void WindowDisplay::show();
void ConsoleDisplay::show();
*/ //}
//对于guidisplay的各个类,大量的重复代码(代码冗余,维护难度加大)
//解决办法:分析“变”与“不变”
//任何绘图的基础都时画点,画法不一样;
//不同GUI,实现画点的接口API不同;
//把变与不变分离开来,抽象出新的接口;
//分离(抽象)新的接口; /*
分离出新的接口:
Bridge模式
把抽象部分与实现部分分离,使他们可以独立变化
class Display
{
public:
virtual void show(float load,long totalMemory,long usedMemory,
float latency) = 0;
virtual ~Display() {}
}; class ConsoleDisplay:public Display
{
public:
void show(float load,long totalMemory,long usedMemory,float latency)
{
cout <<"load=" << load << endl;
cout << "totalMemory=" << totalMemory << endl;
cout << "usedMemory=" << usedMemory << endl;
cout << "latency=" << latency << endl;
}
};
新的接口
class GUIDisplay:public Display
{
public:
//virtual void show(float load,long totalMemory,long usedMemory,
float latency) = 0;
GUIDisplay(GUIDisplayImpl* impl):m_impl(impl) {}
~GUIDisplay();
GUIDisplay(const GUIDisplay &d);
GUIDisplay& operator=(const GUIDisplay &d); protected:
void drawLine(int a,int b, int c, int d);
void drawRect(int a, int b, int c, int d);
//...
private:
void drawPoint(int x, int y);
void drawText(int a, int b,string text);
GUIDisplayImpl* m_impl;
} //
//新的接口定义与使用
class GUIDisplayImpl
{
int use;
friend class GUIDisplay;
public:
GUIDisplayImpl():use(1){}
virtual void drawPoint(int x, int y) = 0;
virtual void drawText(int a , int b, string text) = 0;
}; void GUIDisplay::drawPoint(int x, int y)
{
m_impl->drawPoint(x,y);
} void GUIDisplay::drawText(int x, int y, string text)
{
m_impl->drawText(x,y,text);
} 实现新的接口
class WindowDisplayImpl:public GUIDisplayImpl
{
public:
WindowDisplayImpl() {//init it here...}
~WindowDisplayImpl();
void drawPoint(int x,int y);
void drawText(int x, int y, string text);
} void WindowDisplayImpl::drawPoint(int x, int y)
{
SetPixel(hdc,x,y,foreColor);
} void windowsDisplayImpl::drawText(int x,int y, string text)
{
TextOut(hdc,x,y,text.c_str(),text.len());
} class XWinDisplayImpl:public GUIDisplayImpl
{
public:
XWinDisplayImpl(){//init it here...}
~XWinDisplayImpl() {}
void drawPoint(int x, int y);
void drawText(int x, int y,string text);
} void XWinDisplayImpl::drawPoint(int x,int y)
{
XDrawPoint(display,win,gc,x,y);
} void XWinDisplayImpl::drawText(int x,int y,string text)
{
XDrawString(display,win,gc,x,y,text,text.len());
} void GUIDisplay::drawLine(int x1,int y1, int x2, int y2)
{
for(int x =x1;x < x2;x++)
{
y = x1 + (x-x1)*(y2-y1)/(x2-x1);
drawPoint(x,y);
}
} void GUIDisplay::drawRect(int x1,int y1,int x2, int y2)
{
drawLine(x1,y1,x2,y1);
drawLine(x2,y1,x2,y2);
drawLine(x1,y1,x1,y2);
drawLine(x1,y2,x1,y1);
} 另外一个层面的可变部分:使用继承实现GUIDisplay
class Layout1:public GUIDisplay
{
public:
Layout1(GUIDisplayImpl *impl):GUIDisplay(impl){}
void show(float load,long totalMemory,long usedMemory,float latency);
} void Layout1::show(float load,long totalMemory,long usedMemory,float latency)
{
drawRect(10,10,300,20);
drawText(10,10,float2str(load));
//.....
} class Layout2:public GUIDisplay
{
public:
Layout2(GUIDisplayImpl *impl):GUIDisplay(impl){}
void show(float load,long totalMemory,long usedMemory,float latency);
} void Layout2::show(float load,long totalMemory,long usedMemory,float latency)
{
drawRect(10,10,30,300);
int miny = load*290/100 + 10;
for(int y = 300; y > miny; y-=3)
{
}
}

C++程序设计方法6:算法横向拆分的更多相关文章

  1. Atitit.软件中见算法 程序设计五大种类算法

    Atitit.软件中见算法 程序设计五大种类算法 1. 算法的定义1 2. 算法的复杂度1 2.1. Algo cate2 3. 分治法2 4. 动态规划法2 5. 贪心算法3 6. 回溯法3 7. ...

  2. 《程序设计方法》【PDF】下载

    内容简介 <程序设计方法>主要以方法为主导,结合C语言,把程序设计方法学研究中若干成熟的理论和方法用通俗易懂的语言描述出来.<程序设计方法>还选取趣味性强.技巧性高.能够启发学 ...

  3. mooc- 基本程序设计方法week1,week2

    学习了第一单元我们几本可以写出10行左右的代码. week1:python编程之基本方法 1.从计算机到程序设计语言: 理解计算机:计算机是能够根据一组指令操作数据的机器. 功能性:可以进行数据计算 ...

  4. 机器学习理论提升方法AdaBoost算法第一卷

    AdaBoost算法内容来自<统计学习与方法>李航,<机器学习>周志华,以及<机器学习实战>Peter HarringTon,相互学习,不足之处请大家多多指教! 提 ...

  5. Mysql表的横向拆分与纵向拆分

    表的拆分分为横向拆分(记录的拆分)和纵向拆分(字段的拆分).拆分表的目的:提高查询速度. 1.横向拆分 我们从一个案例去解释,情景是这样的:某某博客,有50W的博客量,有2w的用户,发现随着用户和博客 ...

  6. 08_提升方法_AdaBoost算法

    今天是2020年2月24日星期一.一个又一个意外因素串连起2020这不平凡的一年,多么希望时间能够倒退.曾经觉得电视上科比的画面多么熟悉,现在全成了陌生和追忆. GitHub:https://gith ...

  7. web开发 小方法1-禁止横向滚动

    最近学了学做了个公司的网站  总结了一些小方法 比如取消横向滚动条并禁止的横向滚动 这样就可以吧超出的切掉让网页更和谐 在body 标签 body{ text-align: center; overf ...

  8. js数组sort排序方法的算法

    说明一下,ECMAScript没有定义使用哪种排序算法,各个浏览器的实现方式会有不同.火狐中使用的是归并排序,下面是Chrome的sort排序算法的实现. sort方法源码 DEFINE_METHOD ...

  9. C++程序设计方法4:函数模板

    函数模板 有些算法与类型无关,所以可以将函数的参数类型也定义为一种特殊的“参数”,这样就得到“函数模板” 定义函数模板的方法:template<typename T> 返回类型 函数名称( ...

随机推荐

  1. POJ 2001 Shortest Prefixes(字典树活用)

    Shortest Prefixes Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21651   Accepted: 927 ...

  2. python--使用队列结构来模拟烫手山芋的游戏

    基本功,磨起来. # coding = utf-8 class Queue: def __init__(self): self.items = [] def is_empty(self): retur ...

  3. OpenJDK-study-001 windows上安装Mercurial 4.4.1 克隆OPENJDK版本库

     下载安装 1.下载Mercurial 进入https://www.mercurial-scm.org/wiki/Mercurial下载,windows上傻瓜式安装的,安装好之后,命令行进入安装目录, ...

  4. [转] UniCode编码表

    Unicode编码则是采用双字节16位来进行编号,可编65536字符,基本上包含了世界上所有的语言字符,它也就成为了全世界一种通用的编码,而且用十六进制4位表示一个编码,非常简结直观,为大多数开发者所 ...

  5. 场景/故事/story——寻物者发布消息场景、寻失主发布消息场景、消息展示场景、登录网站场景

    1.背景:(1)典型用户:吴昭[主要]  尤迅[次要] 王丛[次要] 佑豪[次要](2)用户的需求/迫切需要解决的问题a.吴昭:经常在校园各个地方各个时间段,丢失物品需要寻找.b.吴昭:偶尔浏览一下最 ...

  6. 给定一个非负索引 k,其中 k ≤ 33,返回杨辉三角的第 k 行。

    从第0行开始,输出第k行,传的参数为第几行,所以在方法中先将所传参数加1,然后将最后一行加入集合中返回. 代码如下: public static List<Integer> generat ...

  7. 非对称加密算法-RSA算法

    一.概述 1.RSA是基于大数因子分解难题.目前各种主流计算机语言都支持RSA算法的实现 2.java6支持RSA算法 3.RSA算法可以用于数据加密和数字签名 4.RSA算法相对于DES/AES等对 ...

  8. FZU 2254 英语考试 (最小生成树)

    在过三个礼拜,YellowStar有一场专业英语考试,因此它必须着手开始复习. 这天,YellowStar准备了n个需要背的单词,每个单词的长度均为m. YellowSatr准备采用联想记忆法来背诵这 ...

  9. JVM之基本结构

    1. Java虚拟机的架构 1.1 Java的NIO库允许Java程序使用直接内存,访问直接内存的速度优于Java堆.出于性能的考虑,读写频繁的场合会考虑使用直接内存. 1.2 本地方法栈和Java栈 ...

  10. c++简单学习

    在c++中我们很容易遇到字符串的分割处理问题,这种问题通常比较容易,但由于我比较菜,花费了一定时间去思考一个和字符串相关的题,该题的大概思路是利用取模运算后,将得到的单个字符进行分析,主要考察到了字符 ...