<iframe align="top" marginwidth="0" marginheight="0" src="http://www.zealware.com/csdnblog01.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
Delphi之東進模擬語音卡(D160A)可復用源碼
作者:成曉旭
Blog
:
http://blog.csdn.net/cxxsoft
(
聲明:歡迎轉載,請保證文章的完整性
)
設計簡介:
1、
將卡、通道分別單獨進行設計與封裝。
2、
所有的外部操作接口都封裝在卡類這一類。
3、
在我的項目中,在卡類這一級還增加了適配器或者代理,分別實現了
Adapter
或
Proxy
模式;以盡可能地解耦卡設備的實現細節與具體應用業務之間的關系。因為,我們的系統中使用了幾家不同的卡設備,另一方面,這些卡設備,在不同的軟件系統中,又有不同的業務應用需求。
4、
當然,卡這一級,也可以實現一個統一的接口,這樣對外部可以表現出相對統一的行為,以方便業務層代碼的調用,比如說:在數據采集的應用中,統一的接口可以讓采集控制層不必依賴于具體的采集設備和通信方式,可以一致地實現數據收發,不管通信方式是
RS232
、
RS485
、
TCP/IP
、
PSTN
,還是別的方式或者通信設備。
5、
在通道設計中,核心的就是一個“狀態機模式”,通過輪巡通道狀態來管理硬件卡設備,并且,還自己設計了一個業務級的“業務狀態機”,來抽象業務方面需要關心的“業務狀態”,通過增加“業務狀態機”這樣一個中間層,以解耦業務狀態與設備狀態之間的依賴。
(
這一點,在我看到的所有卡廠商提供的各類
Demo
程序里面都沒有這樣做,這也無形中誤導了很多的開發人員,我看到的所有應用軟件開發的源碼都是:設備細節、尤其是通道狀態,與業務邏輯代碼緊緊地耦合在一起,難解難分
)
。
6、
此設計的另一個亮點是:
IoC
模式的應用
(2004
年自己在設計此類時還不知道這個概念,全憑自己的經驗總結出這樣的設計
)
。對通道進入“呼入成功”、“呼出成功”等業務狀態的調用代碼從通道類是解耦出來:設計一個接口,在各個業務狀態的處理方法中,再調用接口方法,將具體的業務處理邏輯委托給實現此接口的對象。并且這個接口的實現是通過“依賴注入”實現
IoC
的。這樣設計,就達到了很好的可復用性和靈活性。
7、
當然,更好的實現可以采用
AOP(
面向方法編程
)
的思想或者實現技術,這樣可復用性更好,如此設計,在業務與卡方法的調用之間,耦合度將是最低的。
8、
目前的版本,沒有在代碼中體現接口的實現
……
9、
類圖
(
以后補上
)
:
10、卡類源碼:
//
------------------------------------------------------------------------------
//
//
產品名稱:成曉旭的個人軟件Delphi源碼庫
//
產品版本:CXXSoftdelphicodesourcelib2.0
//
模塊名稱:Delphi之東進模擬語音卡類
//
模塊描述:
//
單元文件:unDJCard160A.pas
//
開發作者:成曉旭
//
備注:任何人使用此文件時,請保留此段自述文件,謝謝!
//
開發時間:2004-08-03
//
修改歷史:
//
修改描述:
//
------------------------------------------------------------------------------
unitunDJCard160A;
interface
uses
Windows,
unDJTC08a32,unDJNewSig,
unBaseDefine,unDJ160ADefine,
unDJChanne160A;
type
TCXXCommCard160A
=
class
(TObject)
private
ChannelNumber:Word;
channelObject:arrayofTCXXDJChannel160A;
OnCardChannelState:TTrunkStatusEvent;
procedureStop();
procedureReleaseCommDevice();
functionGetChannelObjectOrder(
const
aChannelID:Word):Word;
public
constructorCreate(
const
trunkEvent:TTrunkStatusEvent);
destructorDestroy();
override
;
functionLoadCommDevice(
const
loadAll:boolean
=
false
):boolean;
functionStartup():boolean;
functionGetAFreeChannel():Word;
functionGetChannelNumber():Word;
functionDialPhone(
const
aChannelID:Word;
const
DialPhoneNumber:PChar):boolean;
functionHangUp(
const
aChannelID:Word):boolean;
end;
implementation
...
{TCXXCommCard160A}
constructorTCXXCommCard160A.Create(
const
trunkEvent:TTrunkStatusEvent);
begin
ChannelNumber:
=
0
;
Self.OnCardChannelState:
=
trunkEvent;
end;
destructorTCXXCommCard160A.Destroy;
var
Loop:Word;
begin
Stop();
if
(Length(channelObject)
>
0
)and(channelNumber
>
0
)then
begin
for
Loop:
=
0
toChannelNumber
-
1
do
begin
if
Assigned(channelObject[Loop])then
begin
channelObject[Loop].Free();
channelObject[Loop]:
=
nil;
end;
end;
end;
ReleaseCommDevice();
end;
functionTCXXCommCard160A.DialPhone(
const
aChannelID:Word;
const
DialPhoneNumber:PChar):boolean;
var
K:Word;
begin
Result:
=
false
;
K:
=
GetChannelObjectOrder(aChannelID);
if
(K
ErrorTrunkNumber)and(Assigned(channelObject[K]))then
begin
Result:
=
channelObject[K].DialPhone(DialPhoneNumber);
end;
end;
procedureTCXXCommCard160A.ReleaseCommDevice();
begin
DisableCard();
FreeDrv();
end;
functionTCXXCommCard160A.GetAFreeChannel():Word;
var
Loop:Word;
begin
Result:
=
ErrorTrunkNumber;
for
Loop:
=
Low(channelObject)toHigh(channelObject)
do
begin
if
(channelObject[Loop].GetChannelType()
=
ctEmpty)then
continue
;
if
(channelObject[Loop].GetChannelStatus()
=
atsFree)then
begin
Result:
=
channelObject[Loop].GetChannelID();
break
;
end;
end;
end;
functionTCXXCommCard160A.GetChannelNumber():Word;
begin
Result:
=
channelNumber;
end;
functionTCXXCommCard160A.GetChannelObjectOrder(
const
aChannelID:Word):Word;
var
Loop:Word;
begin
Result:
=
ErrorTrunkNumber;
for
Loop:
=
Low(channelObject)toHigh(channelObject)
do
begin
if
(channelObject[Loop].GetChannelID
=
aChannelID)then
begin
Result:
=
Loop;
break
;
end;
end;
end;
functionTCXXCommCard160A.HangUp(
const
aChannelID:Word):boolean;
var
K:Word;
begin
Result:
=
false
;
K:
=
GetChannelObjectOrder(aChannelID);
if
(K
ErrorTrunkNumber)and(Assigned(channelObject[K]))then
begin
channelObject[K].ChannelHangUp();
Result:
=
true
;
end;
end;
functionTCXXCommCard160A.LoadCommDevice(
const
loadAll:boolean):boolean;
const
loadEmpty
=
true
;
var
Loop,tempNumber:Word;
isFlag:LongInt;
functionCheckLoadTrunk():boolean;
begin
Result:
=
loadAllor((NOTloadAll)and(TChannelType(CheckChType(Loop))
ctEmpty));
end;
begin
isFlag:
=
LoadDRV();
Result:
=
(isFlag
=
0
);
if
NOTResultthenExit;
tempNumber:
=
CheckValidCh();
Result:
=
EnableCard(tempNumber,
1024
*
8
)
=
0
;
if
NOTResultthen
begin
FreeDrv();
Exit;
end;
Result:
=
Sig_Init()
=
1
;
if
NOTResultthenExit;
SetBusyPara(
700
);
SetPackRate(PACK_64KBPS);
channelNumber:
=
tempNumber;
SetLength(channelObject,channelNumber);
for
Loop:
=
0
tochannelNumber
-
1
do
begin
if
CheckLoadTrunk()then
begin
channelObject[Loop]:
=
TCXXDJChannel160A.Create(OnCardChannelState);
channelObject[Loop].CreateCommChannel(Loop);
end;
end;
end;
functionTCXXCommCard160A.Startup():boolean;
var
Loop:integer;
begin
for
Loop:
=
0
tochannelNumber
-
1
do
begin
channelObject[Loop].Resume();
end;
Result:
=
true
;
end;
procedureTCXXCommCard160A.Stop();
var
Loop:integer;
begin
for
Loop:
=
0
tochannelNumber
-
1
do
begin
channelObject[Loop].Suspend();
channelObject[Loop].Terminate();
channelObject[Loop]:
=
nil;
end;
end;
end.
11、
通道類源碼:
//
------------------------------------------------------------------------------
//
//
產品名稱:成曉旭的個人軟件Delphi源碼庫
//
產品版本:CXXSoftdelphicodesourcelib2.0
//
模塊名稱:Delphi之東進模擬語音卡通道類
//
模塊描述:
//
單元文件:unDJChanne160A.pas
//
開發作者:成曉旭
//
備注:任何人使用此文件時,請保留此段自述文件,謝謝!
//
開發時間:2004-08-03
//
修改歷史:
//
修改描述:
//
------------------------------------------------------------------------------
unitunDJChanne160A;
interface
uses
Windows,Classes,SysUtils,
unBaseDefine,unDJ160ADefine,
unDJTC08a32,unDJNewSig;
Type
TCXXDJChannel160A
=
class
(TThread)
//
TCXXDJChannel160A=class(TObject)
private
channelType:TChannelType;
oldChannelState,channelState:TTrunkState;
channelID:Word;
phoneNumber:
string
;
dtmfString:
string
;
isConntectd:boolean;
isDialOut:boolean;
aTrunkState:TTrunkStatus;
procedureInformTrunkStatus(
const
aMsgFlag:TLVOperateFlag);
procedureClearTrunkStatus();
functionCheckSigHangup():boolean;
functionCheckCallIn():boolean;
functionSwitchOnCallIn():boolean;
procedureProcessCallInSuccess();
procedureProcessDialSuccess();
procedureProcessCheckDialSend();
protected
procedureExecute();
override
;
public
strMessage:
string
;
OnChannelState:TTrunkStatusEvent;
constructorCreate(
const
trunkEvent:TTrunkStatusEvent);
destructorDestroy();
override
;
procedureCreateCommChannel(
const
aChennelID:Word);
procedureChannelProcessor();
functionGetChannelID():Word;
functionGetChannelStatus():TTrunkState;
functionGetChannelType():TChannelType;
functionDialPhone(
const
DialPhoneNumber:PChar):boolean;overload;
functionDialPhone(
const
DialPhoneNumber:PChar;
const
PreDialNumber:PChar):boolean;overload;
procedureChannelHangUp();
functionGetDialOut():boolean;
end;
implementation
...
{TCXXDJChannel160A}
procedureTCXXDJChannel160A.ChannelHangUp();
begin
isDialOut:
=
false
;
StopSigCheck(channelID);
HangUp(channelID);
Sig_ResetCheck(channelID);
StartSigCheck(channelID);
InitDTMFBuf(channelID);
ClearTrunkStatus();
InformTrunkStatus(lvofUpdate);
end;
procedureTCXXDJChannel160A.ChannelProcessor();
var
dState:Word;
begin
PUSH_PLAY();
FeedSigFunc();
CheckCallIn();
case
channelStateof
atsFree:
begin
//
end;
atsCallIning:
begin
SwitchOnCallIn();
end;
atsCallInSuccess:
begin
if
CheckSigHangup()thenExit;
ProcessCallInSuccess();
end;
atsCheckSendDial:
begin
ProcessCheckDialSend();
end;
atsDialing:
begin
dState:
=
Sig_CheckDial(channelID);
case
dStateof
//
S_NORESULT:
S_CONNECT:
begin
channelState:
=
atsDialSuccess;
isConntectd:
=
true
;
end;
S_BUSY,
S_NOBODY,
S_NODIALSIG,
S_NOSIGNAL:
begin
channelState:
=
atsHangOff;
end;
end;
strMessage:
=
'
<spa
分享到:
-
瀏覽: 1292150 次
-
性別:
-
來自: 杭州
-
評論