經典軟體體系結構風格(二)
1.基於事件的隱式呼叫風格
基本元件:物件或過程,並分類為以下更小的元件
–過程或函式,充當事件源或事件處理器的角色
–事件
連線件:事件-過程繫結
–過程(事件處理器,事件的接收和處理方) 向特定的
事件進行註冊;
–元件(事件源) 釋出事件;
–當某些事件被髮布(觸發) 時,向其註冊的過程被隱式呼叫;
–呼叫的次序是不確定的;
優點
§支援實現互動式系統(使用者輸入/網路通訊)
§非同步執行,不必同步等待執行結果
§對事件的併發處理將提高系統性能;
缺點:
分散式控制方式使系統的同步、驗證和除錯變得異常困難:
–元件放棄了對系統計算的控制,難以控制各模組之間的處理次序。一個元件觸發一個事件時,不能確定其它元件是否會響應它。而且即使它知道事件註冊了哪些元件的構成,它也不能保證這些過程被呼叫的順序。
–既然過程的語義必須依賴於被觸發事件的上下文約束,關於正確性的推理則難以保證。
–傳統的基於先驗和後驗條件的驗證變得不可能。
程式一:
package com.button; import java.awt.Button; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Label; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; class BtnLabelAction extends Frame implements ActionListener { //宣告視窗類(BtnLabelAction)並實現動作事件介面(ActionListener) Label prompt; Button btn; void CreateWindow() { setTitle("MyButton"); prompt = new Label("你好"); //建立標籤物件 btn = new Button("操作"); //建立按鈕物件 setLayout(new FlowLayout()); //佈局設計,用於安排按鈕、標籤的位置 add(prompt); //將標籤放入容器 add(btn); //將按鈕放入容器 btn.addActionListener(this); //將監聽器(窗體物件本身)註冊給按鈕物件 setSize(300,100); setVisible(true); } public void actionPerformed(ActionEvent e) //介面ActionListener的事件處理方法 { if(e.getSource()==btn) //判斷動作事件是否是由按鈕btn引發的 if(prompt.getText()=="你好") prompt.setText("再見"); else prompt.setText("你好"); } } public class BtnTest { public static void main(String[] args) { // TODO Auto-generated method stub BtnLabelAction bla=new BtnLabelAction(); bla.CreateWindow(); } }
程式二:
package com.button; import java.awt.Button; import java.awt.Color; import java.awt.FlowLayout; import java.awt.Frame; import java.awt.Label; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import javax.swing.JTextField; class ButtonLabelTest extends Frame implements ActionListener{ Label label; JTextField textField; Button button; void CreateView(){ setSize(300, 200); setTitle("基於事件的隱式呼叫風格"); setBackground(Color.orange); label=new Label("你的姓名:"); textField=new JTextField(); textField.setText("楊旭"); button=new Button("得到你的姓名"); setLayout(new FlowLayout()); add(label); add(textField); add(button); button.addActionListener(this); setVisible(true); } public void actionPerformed(ActionEvent e) { if(e.getSource()==button){ if(textField.getText()=="楊旭"){ textField.setText("海哥"); } else{ textField.setText("楊旭"); } } } } public class ButtonTest { public static void main(String[] args) { // TODO Auto-generated method stub ButtonLabelTest test=new ButtonLabelTest(); test.CreateView(); } }
2.管道-過濾器軟體體系結構風格
元件:過濾器,處理資料流
&&一個過濾器封裝了一個處理步驟
–-資料來源點和資料終止點可以看作是特殊的過濾器過濾器對輸入流進行處理、轉換,處理後的結果在輸出端流出。
§&每個元件都有輸入/輸出集合,元件在輸入處讀取資料流,經過內部處理,在輸出處生成資料流。
連線件:管道,連線一個源和一個目的過濾器
–-轉發資料流
–-資料可能是ASCII字元形成的流連線件位於過濾器之間,起到資訊流的導管的作用,被稱為管道。接件就象是資料流傳輸的管道,將一個過濾器的輸出傳到另一過濾器的輸入。
—管道過濾器優點:由於每個元件的行為不受其他元件的影響,整個系統的行為易於理解
§&系統中的元件具有良好的隱蔽性和高內聚、低耦合的特點;
–—支援軟體複用:
•允許設計者將整個系統的輸入/輸出行為看成是多個過濾器的行為的簡單合成;
•只要提供適合在兩個過濾器之間傳送的資料,任何兩個過濾器都可被連線起來;
—系統維護和增強系統性能簡單:
•新的過濾器可以新增到現有系統中來,舊的可以被改進的過濾器替換掉;允許對一些如吞吐量、死鎖等屬性的分析;
§支援並行執行:
–每個過濾器是作為一個單獨的任務完成,因此可與其它任務並行執行。
&*管道-過濾器風格的缺點:
§&通常導致程序成為批處理的結構
–這是因為雖然過濾器可增量式地處理資料,但它們是獨立的,所以設計者必須將每個過濾器看成一個完整的從輸入到輸出的轉換;
§&不適合處理互動的應用
—當需要增量地顯示改變時,這個問題尤為嚴重;處理兩個獨立但又相關的資料流是可能會遇到困難
§&在資料傳輸上沒有通用的標準,每個過濾器都增加了解析和合成資料的工作,這樣就導致了系統性能下降,並增加了編寫過濾器的複雜性。
–—絕大部分處理時間消耗在格式轉換上(需要對資料傳輸進行特定的處理時,會導致對於每個過濾器的解析輸入和格式化輸出要做更多的工作,帶來系統複雜性的上升)
程式:
package com.person;
import java.io.IOException;
import java.io.PipedInputStream;
import java.io.PipedOutputStream;
class Sender extends Thread
{
PipedOutputStream out=new PipedOutputStream();
public PipedOutputStream getOut()
{
return out;
}
@Override
public void run()
{
// TODO Auto-generated method stub
String str="海哥,你好!\n";
try
{
out.write(str.getBytes());
out.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
class Receiver extends Thread
{
PipedInputStream in=new PipedInputStream();
public PipedInputStream getIn()
{
return in;
}
@Override
public void run()
{
// TODO Auto-generated method stub
byte [] buf = new byte[1024];
try
{
int len=in.read(buf);
System.out.println("下面是Sender函式接受到的資料:\n"+new String(buf, 0,len));
in.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public class TestPigedPerson
{
public static void main(String[] args)
{
// TODO Auto-generated method stub
Sender S=new Sender();
Receiver R=new Receiver();
PipedInputStream In=R.getIn();
PipedOutputStream Out=S.getOut();
try
{
In.connect(Out);//兩個輸入輸出相連
R.start();
S.start();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
截圖: