MarvellousWorks公司最近開始向大客戶提供後台接入服務,允許客戶通過該服務與其多個在線業務進行B2B集成。
大體處理流程如下:
1) 客戶通過消息隊列將請求以報文的形式發給MarvellousWorks公司的“隊列服務平台”。
2) 為了安全考慮,“消息平台”的處理邏輯主動從“隊列服務平台”抓取最新提交的報文。
3) 抓取新報文後,“消息平台”對報文進行拆解,讀取其中的信息並驗證其有效性。
4) “消息平台”將拆解並驗證有效地報文信息寫入數據庫
限制:
1) 報文數據均為XML格式,其 XML Schema預先由MarvellousWorks定義並發布,各家客戶遵照執行
2) 由於客戶使用的隊列產品各異,所以“隊列服務平台”計劃支持微軟MSMQ和IBM MQ,後續還可能支持ORACLE的Advanced Queue和BEA的MessageQ。
3) 由於MarvellousWorks的各個在線業務建立時間不同,所以數據庫既有ORACLE、也有MySQL和SQL Server。
現在由你作為架構師設計“消息平台”的服務程序。
1、 隊列訪問接口和數據庫訪問接口的定義如下:
/// <summary>
/// 隊列訪問接口
/// </summary>
interface IQueue
{
XmlDocument Peek();
XmlDocument Dequeue();
}
/// <summary>
/// 各在線業務數據實體的基類
/// </summary>
abstract class EntryBase { }
/// <summary>
/// 這裡為了簡化示例,將所有業務實體寫如數據庫前轉換為ADO.NET自帶的DataRow類型
/// </summary>
interface IEntryDataConverter
{
DataRow ToDataRow(EntryBase entry);
}
/// <summary>
/// 數據庫訪問接口
/// </summary>
interface IDatabase
{
IEntryDataConverter DataConverter { get; set; }
void Write(EntryBase entry);
void Write(IEnumerable<EntryBase> entries);
}
2、 請用本章介紹的適配器模式設計“消息平台”處理接口,並用建立一個簡單的原型,通過單元測試驗證你的思路。
3、 由於報文數據種類眾多,請用本章介紹的數據適配機制配合上面的消息處理接口完成一個數據適配原型,並通過單元測試驗證。
提示:
為保持“消息平台”處理邏輯的穩定,建議考慮Adapter-Adapter級聯的方式,完成報文抓取到消息入庫的過程
參考答案
1、這裡為了簡化示例,將所有業務實體寫如數據庫前轉換為ADO.NET自帶的DataRow類型
2、所有的調用接口都采用了空數據
目標主要是通過單元測試驗證結構的有效性
1、模擬用的隊列產品接口及其適配器
class Msmq
{
string current;
/// <summary>
/// 不兼容的接口,相當於Peek()
/// </summary>
public string Head
{
get
{
Trace.WriteLine("Msmq.Head");
current = Guid.NewGuid().ToString();
return current;
}
}
/// <summary>
/// 不兼容的接口,相當於Dequeue()
/// </summary>
/// <returns></returns>
public string GetHead()
{
Trace.WriteLine("Msmq.GetHead()");
var result = current;
current = string.Empty;
return result;
}
}
class MsmqAdapter : IQueue
{
Msmq queue = new Msmq();
public XmlDocument Peek()
{
Trace.WriteLine("MsmqAdapter.Peek()");
Trace.WriteLine(queue.Head);
return null;
}
public XmlDocument Dequeue()
{
Trace.WriteLine("MsmqAdapter.Dequeue()");
Trace.WriteLine(queue.GetHead());
return null;
}
}
class IbmMq : Queue<string>
{
string lastest;
public new string Peek()
{
lastest = Guid.NewGuid().ToString();
base.Enqueue(lastest);
Trace.WriteLine("IbmMq.Peek()");
return base.Peek();
}
public new string Dequeue()
{
Trace.WriteLine("IbmMq.Dequeue()");
return base.Dequeue();
}
}
class IbmMqAdapter : IQueue
{
IbmMq queue = new IbmMq();
public XmlDocument Peek()
{
Trace.WriteLine("IbmMqAdapter.Peek()");
Trace.WriteLine("Message : " + queue.Peek());
return null;
}
public XmlDocument Dequeue()
{
Trace.WriteLine("IbmMqAdapter.Dequeue()");
Trace.WriteLine("Message : " + queue.Dequeue());
return null;
}
}
2、模擬用的數據庫產品接口
class OracleDB
{
public void WriteData(string[][] data)
{
Trace.WriteLine("OracleDb.WriteData(string[][] data)");
}
}
class SqlServer
{
public void ExecuteNonSql(DataSet data)
{
Trace.WriteLine("SqlServer.ExecuteNonSql(DataSet data)");
}
public void InsertOneRecord(DataRow data)
{
Trace.WriteLine("SqlServer.InsertOneRecord(DataRow data)");
}
}
class MySqlDatabase
{
public void ExecuteCommand(string sql)
{
Trace.WriteLine("MySqlDatabase.ExecuteCommand(string sql)");
}
}
3、模擬用的各類示例的業務實體
class Order : EntryBase { }
class DeliveryOrder : EntryBase { }
class WarehouseEntry : EntryBase { }
class InventoryList : EntryBase { }
4、模擬的數據適配接口以及面向個業務實體類型的實體數據適配類型
interface IMessageConverter
{
IEnumerable<EntryBase> ConvertMessageToQuerable(XmlDocument message);
}
abstract class DatabaseAdapterBase : IDatabase
{
public IEntryDataConverter DataConverter { get; set; }