三种典型的数据流风格
§ Batch Sequential (批处理)
§ Pipe-and-Filter (管道-过滤器)
§ Process Control(过程控制,3.7)
批处理风格:
直观结构
批处理风格-基本定义
§每个处理步骤是一个独立的程序
§每一步必须在前一步结束后才能开始
§数据必须是完整的,以整体的方式传递
§典型应用:
–传统的数据处理
–程序编译/CASE(computer aided software engineering)工具
批处理风格-基本构成
§基本组件:独立的应用程序
§连接件:某种类型的媒质(magnetic tape)
§表达拓扑结构:连接件定义了相应的数据流图
§每一步骤必须在前一步骤完全结束之后方能开始
程序:#include <iostream>
#include<fstream>
using namespace std;
bool writeFile(constchar* strPath,char strConcern[],int length)
{
ofstream outfile;
outfile.open(strPath,ios::app);
if(!outfile)
{
cerr<<"openerror!"<<endl;
return false;
}
outfile.write(strConcern,length);
outfile.close();
return true;
}
bool ReadFile(constchar * strPath,char strConcern[],int length)
{
ifstream infile;
infile.open(strPath,ios::binary);
if(!infile)
{
cerr<<"openerror"<<endl;
return false;
}
while(!infile.eof())
{
infile.read(strConcern,length);
}
return true;
}
bool factory1()
{
char str[20]="helloworld";
charstrpath[20]="E:\\text1.txt";
bool b=writeFile(strpath,str,sizeof(str));
if(!b)
{
return false;
}
return true;
}
bool factory2()
{
char str[20];
char strpath[20]="E:\\text1.txt";
bool b=ReadFile(strpath,str,sizeof(str));
cout<<str<<endl;
cout<<str<<endl;
charstrpath1[20]="E:\\text2.txt";
boolbw=writeFile(strpath1,str,sizeof(str));
bw=writeFile(strpath1,"第二道工序",sizeof(str));
if(!b||!bw)
{
return false;
}
return true;
}
int main()
{
char strpath[40]="E:\\text2.txt";
char str[20];
bool b1=factory1();
bool b2=factory2();
bool b=ReadFile(strpath,str,sizeof(str));
if(b&&b1&&b2)
{
cout<<str<<endl;
}
//cout << "Hello world!"<< endl;
return 0;
管道过滤器风格:
组件:过滤器,处理数据流
–一个过滤器封装了一个处理步骤
–数据源点和数据终止点可以看作是特殊的过滤器过滤器对输入流进行处理、转换,处理后的结果在输出端流出。§每个组件都有输入/输出集合,组件在输入处读取数
据流,经过内部处理,在输出处生成数据流。
连接件:管道,连接一个源和一个目的过滤器
–转发数据流
–数据可能是ASCII字符形成的流连接件位于过滤器之间,起到信息流的导管的作
用,被称为管道。接件就象是数据流传输的管道,将一个过滤器的输出传到另一过滤器的输入。
管道过滤器优点:由于每个组件的行为不受其他组件的影响,整个系统的行为易于理解
§系统中的组件具有良好的隐蔽性和高内聚、低耦合的特点;
–支持软件复用:
•允许设计者将整个系统的输入/输出行为看成是
多个过滤器的行为的简单合成;
•只要提供适合在两个过滤器之间传送的数据,任何两个过滤器都可被连
接起来;
–系统维护和增强系统性能简单:
•新的过滤器可以添加到现有系统中来,
旧的可以被改进的过滤器替换掉;
允许对一些如吞吐量、死锁等属性的分析;
§支持并行执行:
–每个过滤器是作为一个单独的任务完成,因此可与
其它任务并行执行。
管道-过滤器风格的缺点:
§通常导致进程成为批处理的结构
–这是因为虽然过滤器可增量式地处理数据,但它们
是独立的,所以设计者必须将每个过滤器看成一个
完整的从输入到输出的转换;
§不适合处理交互的应用
–当需要增量地显示改变时,这个问题尤为严重;
处理两个独立但又相关的数据流是可能会遇到困难
§在数据传输上没有通用的标准,每个过滤器都增加
了解析和合成数据的工作,这样就导致了系统性能
下降,并增加了编写过滤器的复杂性。
–绝大部分处理时间消耗在格式转换上(需要对数据传
输进行特定的处理时,会导致对于每个过滤器的解析
输入和格式化输出要做更多的工作,带来系统复杂性
的上升)
过滤器与批处理比较:
程序:管道-过滤器软件体系结构
(1)在dos提示符下输入下面的命令:
dir | more
使得当前目录列表在屏幕上逐屏显示。
dir的输出的是整个目录列表,它不出现在屏幕上而是由于符号“|”的规定,成为下一个命令more的输入,more命令则将其输入一屏一屏地显示,成为命令行的输出。
(2)Java I/O流中的管道流类PipedInputStream和PipedOutputStream可以方便地实现管道-过滤器体系结构,这两个类的实例对象要通过connect方法连接。
下面程序的功能是sender发送“Hello,receiver! I`m sender”给receiver,然后receiver接受后显示出来并且在前面加上“the following is from sender”的信息。管道流内部在实现时还有大量的对同步数据的处理,管道输出流和管道输入流执行时不能互相阻塞,所以一般要开启独立线程分别执行,顺便复习了多线程操作。
import java.io.*;
import java.util.*;
public class TestPiped{
public static void main(String [] args){
sender s = new sender();
receiver r = new receiver();
PipedOutputStream out = s.getOut();
PipedInputStream in = r.getIn();
try{
in.connect(out);
s.start();
r.start();
}catch(Exception e){
e.printStackTrace();
}
}
}
class sender extends Thread {
PipedOutputStream out = new PipedOutputStream();
publicPipedOutputStream getOut(){
return out;
}
public void run() {
String str = "Hello,receiver ! I`msender\n";
try {
out.write(str.getBytes());
out.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
class receiver extends Thread {
PipedInputStream in = new PipedInputStream();
public PipedInputStream getIn() {
return in;
}
public void run(){
byte [] buf = new byte[1024];
try {
int len = in.read(buf);
System.out.println("the following is from sender:\n"+newString(buf,0,len));
in.close();
}catch(Exception e) {
e.printStackTrace();
}
}
}
程序的执行结果:
thefollowing is from sender:
Hello,receiver ! I`m sender