curtis
18小時前 10220027159dc90f19f7c62a7b84bb00c6453d4c
doc/curtis/OCX_溝通與_抽象層抽換.md
@@ -59,10 +59,10 @@
}
/**
 * 掃描服務抽象介面 (IScanService)
 * 掃描服務抽象介面 (IOCXService)
 * UI 層僅與此介面溝通,不直接操作底層實作
 */
export interface IScanService {
export interface IOCXService {
  initialize(config: ScanConfig): Promise<void>;
  startScan(): Promise<boolean>;
  uploadFiles(): Promise<boolean>;
@@ -75,7 +75,7 @@
 * 實作 A: ActiveX 適配器 (Legacy Adapter)
 * 用於目前環境:UI (TS) -> Delphi Browser -> ActiveX (OCX)
 */
export class ActiveXScanAdapter implements IScanService {
export class ActiveXScanAdapter implements IOCXService {
  private ocx: any;
  constructor() {
@@ -122,7 +122,7 @@
 * 實作 B: Backend Server 適配器 (Future Adapter)
 * 用於未來環境:UI (TS) -> REST API / WebSocket -> Rust/Go Backend
 */
export class BackendServerAdapter implements IScanService {
export class BackendServerAdapter implements IOCXService {
  private apiUrl = "http://localhost:8080/api/scanner";
  async initialize(config: ScanConfig): Promise<void> {
@@ -164,7 +164,7 @@
 * 根據環境自動切換實作
 */
export class ScannerFactory {
  static getService(): IScanService {
  static getService(): IOCXService {
    if ((window as any).OCX_INSTANCE) {
      console.log("偵測到 ActiveX 環境,啟用 ActiveX 適配器");
      return new ActiveXScanAdapter();
@@ -184,14 +184,14 @@
ActiveX 的方法通常是同步阻塞的,而後端 API 是非同步的。
- **建議**:在抽象介面(IScanService)中,所有方法都回傳 Promise。
- **建議**:在抽象介面(IOCXService)中,所有方法都回傳 Promise。
- **原因**:這樣當你未來切換到後端伺服器(fetch API)時,UI 的調用邏輯(await service.startScan())不需要做任何修改。
### **3. 實作「心跳」或「狀態輪詢」**
原本 GetSetInf1~7 主要是靠宿主程式主動去「問」OCX。
- **抽象層建議**:在 IScanService 中實作一個 subscribeStatus(callback) 的觀察者模式。
- **抽象層建議**:在 IOCXService 中實作一個 subscribeStatus(callback) 的觀察者模式。
- **ActiveX 模式下**:在適配器內部啟動一個 setInterval 去輪詢 GetSetInf。
- **未來後端模式下**:適配器改用 **WebSocket** 接收後端主動推播的掃描事件。
- **UI 層感受**:UI 只需要處理 onStatusUpdate 事件,根本不用管底層是用輪詢還是 WebSocket。