Kei*_*ows 7 c# design-patterns
注意:在底部澄清了我的一些问题.
我想知道是否可能有一个(理智的)模式来处理旧主机系统的请求/响应?在下面的示例中,IQ是请求,RSIQ是响应.在第一个示例中,我正在请求所有帐户代码的列表,在第二个请求中,我要求每个帐户代码的关闭日期.由于这些仅通过序数位置链接,因此很容易将数据拉入结构化数据类.在这种情况下,每个响应代表多个记录.
在第二个例子中,我正在为单个记录请求几位信息.在这种情况下,每个响应代表一个记录和一些数据点.
这是客户端发送到服务器以从数据库请求特定信息的消息.
The inquiry message has this general format:
IQ~<msg id>~A<unit#>~B<device type>~D<acct#>~F<password>~G<file>~H<hierarchicrecordpath>~J<field>
**One field from many records**:
Beginning with first share (ordinal zero) on Account 101 return all the Share ID fields in first
message then get all Close Dates in second message. IDs and Close Dates correspond
positionally within the two responses.
IQ~1~A0~BVENDOR~D101~F7777~HSHARE=0~JID=ALL
RSIQ~1~K0~JID=0000~JID=0003~JID=0004~JID=0005~JID=0025~JID=0050
IQ~1~A0~BVENDOR~D101~F7777~HSHARE=0~JCLOSEDATE=ALL
RSIQ~1~K0~JCLOSEDATE=00000000~JCLOSEDATE=20030601~JCLOSEDATE=00000000~JCLOSEDATE=00000000~JCLOSEDATE=00000000~JCLOSEDATE=00000000
**Many fields from one record**:
Using the previous requests get additional information from open shares (two examples).
IQ~1~A0~BVENDOR~D101~F7777~HSHARE#0005~JCLOSEDATE~JSHARECODE~JDIVTYPE~JBALANCE~JAVAILABLEBALANCE
RSIQ~1~K0~JCLOSEDATE=00000000~JSHARECODE=0~JDIVTYPE=2~JBALANCE=234567~JAVAILABLEBALANCE=234567
IQ~1~A0~BVENDOR~D101~F7777~HSHARE#0025~JCLOSEDATE~JSHARECODE~JDIVTYPE~JBALANCE~JAVAILABLEBALANCE
RSIQ~1~K0~JCLOSEDATE=00000000~JSHARECODE=1~JDIVTYPE=5~JBALANCE=654321~JAVAILABLEBALANCE=654321
Run Code Online (Sandbox Code Playgroud)
背景:我已经在我的应用程序中使用了工作单元/存储库模式.每个应用程序都处理多个数据存储(SQL DB,文件,Web服务,套接字等).这个想法是每个存储库公开(完整的)部分数据模型.
我最初的想法是创造我需要在存储库,如特定的调用GetAccounts(acctId)
,并有方法发送正确的请求,然后从所有建立的对象图反应变量,最后返回对象图.
我现在正在寻找一种设计模式来处理这些方法的内部,而无需执行大量的string.Replace()语句或StringBuilder调用.由于任何请求的最大大小为8000个字符,因此您可以看到~J字段可能变得非常复杂.(我仍在寻找可以进入~J字段的所有可能代码.)
小例子:
public List<SymitarAccount> GetAccounts(string accountId)
{
var retAccounts = new List<SymitarAccount>();
// Is there a pattern to do this repetitve but ever changing task? //
// Example: Mock response then handle... //
// NOTE: There will be many request/response calls here, not just one! //
var rsp = @"RSIQ~1~K0~JCLOSEDATE=00000000~JSHARECODE=1~JDIVTYPE=5~JBALANCE=654321~JAVAILABLEBALANCE=654321";
var response = rsp.Split(new[] {'~'});
foreach (var q in response)
{
if (q.StartsWith("J") && q.Contains("="))
{
// get Key Value Pair //
// map KVP to SymitarAccount data point (big ugly switch(){}??) //
sa.Id = // KVP for ID //
sa.Balanace = // KVP for BALANCE //
}
retAccounts.Add(sa);
}
return retAccounts;
}
Run Code Online (Sandbox Code Playgroud)
有什么想法或想法吗?
注意:我正在使用C#(最新).
附加#1:
public List<SymitarAccount> GetAccounts(string accountId)
{
var retAccounts = new List<SymitarAccount>();
// Get all account IDs...
var response = UnitOfWork.SendMessage("IQ~1~A0~BVENDOR~D101~F7777~HSHARE=0~JID=ALL");
ParseResponse(response, ref retAccounts);
// Get all account close dates (00000000 means it is open)...
response = UnitOfWork.SendMessage("IQ~1~A0~BVENDOR~D101~F7777~HSHARE=0~JCLOSEDATE=ALL");
ParseResponse(response, ref retAccounts);
// Get extra info for all OPEN accounts...
foreach (var account in retAccounts.Where(a => !a.IsClosed))
{
var request = "IQ~1~A0~BVENDOR~D101~F7777~HSHARE#[acct]~JCLOSEDATE~JSHARECODE~JDIVTYPE~JBALANCE~JAVAILABLEBALANCE";
request = request.Replace("[acct]", account.Id.ToString("0000"));
response = UnitOfWork.SendMessage(request);
ParseResponse(response, ref retAccounts, account.Id);
}
return retAccounts;
}
private void ParseResponse(string response, ref List<SymitarAccount> accountList, int? id = null)
{
var list = response.Split(new[] {'~'});
var index = 0;
var chain = new ChainInquiryAccountInfo();
var parser = chain.Parser;
foreach (var q in list.Where(q => q.StartsWith("J"))) // && q.Contains("=")))
{
if (accountList.Count < index || accountList[index] == null)
accountList.Add(new SymitarAccount {PositionalIndex = index});
var val = q.Split(new[] {'='});
if ((id.HasValue && accountList[index].Id == id.Value) || !id.HasValue)
accountList[index] = parser.Parse(val, accountList[index]);
index++;
}
}
Run Code Online (Sandbox Code Playgroud)
您的示例实际上是反序列化,不是来自 XML 或 JSON,而是来自某些自定义文本格式。然后,当您创建类并为其字段添加属性以帮助序列化/反序列化时,您可以遵循其他序列化器的方向。我相信这可以称为属性序列化器模式......
让我们创建一些自定义属性来注释序列化类:
[AttributeUsage(AttributeTargets.All, Inherited = false, AllowMultiple = true)]
sealed class SomeDataFormatAttribute : Attribute
{
readonly string name;
// This is a positional argument
public SomeDataFormatAttribute(string positionalString)
{
this.name = positionalString;
}
public string Name
{
get { return name; }
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以将你的数据对象描述为:
class SymitarAccount
{
[SomeDataFormat("CLOSEDATE")]
public string CloseDate;
[SomeDataFormat("SHARECODE")]
public int ShareCode;
}
Run Code Online (Sandbox Code Playgroud)
现在您需要基于反射的序列化器/反序列化器,它将属性字段与字符串进行匹配。这里我使用正则表达式(为了简单起见,没有错误检查):
public class SomeDataFormatDeserializer
{
public static T Deserlize<T>(string str) where T : new()
{
var result = new T();
var pattern = @"RSIQ~1~K0(?:~J(\w+=\d+))*";
var match = Regex.Match(str, pattern);
// Get fields of type T
var fields = typeof(T).GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in fields)
{
// Get out custom attribute of this field (might return null)
var attr = field.GetCustomAttribute(typeof(SomeDataFormatAttribute)) as SomeDataFormatAttribute;
// Find regex capture that starts with attributed name (might return null)
var capture = match.Groups[1].Captures
.Cast<Capture>()
.FirstOrDefault(c => c.Value.StartsWith(attr.Name));
if (capture != null)
{
var stringValue = capture.Value.Split('=').Last();
// Convert string to the proper type (like int)
var value = Convert.ChangeType(stringValue, field.FieldType);
field.SetValue(result, value);
}
}
return result;
}
}
Run Code Online (Sandbox Code Playgroud)
然后你就可以像下面这样简单地使用它:
public static List<SymitarAccount> GetAccounts(string accountId)
{
var retAccounts = new List<SymitarAccount>();
var responses = new List<string>() { @"RSIQ~1~K0~JCLOSEDATE=00000000~JSHARECODE=1" };
foreach (var response in responses)
{
var account = SomeDataFormatDeserializer.Deserlize<SymitarAccount>(response);
retAccounts.Add(account);
}
return retAccounts;
}
Run Code Online (Sandbox Code Playgroud)
注意: SomeDataFormatDeserializer
是为了清晰起见而编写的,而不是为了性能。当然它可以优化(如缓存GetFields
等)
归档时间: |
|
查看次数: |
164 次 |
最近记录: |