好吧,讓我們假設下列關於你的例子:每個用戶(用戶ID)定義不同的查詢處理你遇到數據。
我們的數據容器類...這裏很簡單,只包含一個字符串。
public class Data
{
public string Content { get; set; }
}
下一步,讓我們看看在查詢......可能是使用該接口(可以使用事件,該響應,但讓保持簡單在這裏)。
public interface IQuery
{
Data Process(Data data);
}
你可以通過增加用戶id到IQUERY接口有關係的用戶,但我寧願有另一個接口來解決:
public interface IUserQueryProvider
{
IEnumerable<IQuery> GetQuerysForUser(uint id);
}
這樣你就可以改變你的用戶查詢在單獨的地方解決。
你也會有一個序列化器/轉換器。好的,讓我們在這裏創建一個接口來處理(處理)數據的序列化。
public interface ISerializer
{
string Serialize(Data data);
}
現在,讓我們來看看實現,首先是串行的......沒有做什麼神奇這裏,你應該在你需要的對象的序列化的東西填補(JSON,... )
public class JavascriptSerializer : ISerializer
{
public string Serialize(Data data)
{
return data.Content; //whatever you want do instead for serialization
}
}
現在讓我們轉到我們的查詢。我假設你對設計模式不是很熟悉,而你的意思就像是命令模式(用於處理作業,請參閱我的註釋中的鏈接以獲取有關設計模式的更多信息)。3個實現如下樣本:
public class ReplaceQuery : IQuery
{
private readonly string match;
private readonly string text;
public ReplaceQuery(string match, string text)
{
this.match = match;
this.text = text;
}
public Data Process(Data data)
{
return data.Content.Contains(match) ? new Data {Content = data.Content.Replace(match, text)} : null;
}
}
public class GreetingToQuery : IQuery
{
private readonly string greeting;
private readonly string place;
public GreetingToQuery(string greeting, string place)
{
this.greeting = greeting;
this.place = place;
}
public Data Process(Data data)
{
return data.Content.Contains(greeting) ? new Data {Content = data.Content + place + "."} : null;
}
}
public class LineEndingQuery : IQuery
{
public Data Process(Data data)
{
return data.Content.LastIndexOf(".", StringComparison.Ordinal) == data.Content.Length - 1 &&
data.Content.Length > 0
? new Data {Content = "\n"}
: null;
}
}
如果我們想要解析哪些查詢屬於用戶,我們需要我們的IUserQueryProvider實現。在這種情況下,它只不過是一本字典(但可以輕鬆切換到其他實現)。
public class SampleQueryProvider : Dictionary<uint, IEnumerable<IQuery>>, IUserQueryProvider
{
public IEnumerable<IQuery> GetQuerysForUser(uint id)
{
IEnumerable<IQuery> queries;
TryGetValue(id, out queries);
return queries;
}
}
最後但並非最不重要的......一切的膠水。我在這裏爲我們的「發電機引擎」添加了另一個接口。
public interface IScriptGenerator
{
event Action<string> Script;
void Generate(Data data, IEnumerable<IQuery> queries);
}
爲了使它更靈活的我做了接口/實現以下由拉爾夫·韋斯特法爾推出了一款設計原理稱爲基於事件的組件(EBC)。如果你對這個話題感興趣,Google是你的朋友。
public class SampleScriptGenerator : IScriptGenerator
{
private readonly ISerializer serializer;
public event Action<string> Script;
public SampleScriptGenerator(ISerializer serializer)
{
this.serializer = serializer;
}
public void Generate(Data data, IEnumerable<IQuery> queries)
{
foreach (string serialized in from query in queries select query.Process(data) into result where result != null select serializer.Serialize(result))
{
OnSerialize(serialized);
}
}
private void OnSerialize(string serialized)
{
var handler = Script;
if (handler != null) handler(serialized);
}
}
現在可以把它放在一起,讓我們飛:
static void Main()
{
var generator = new SampleScriptGenerator(new JavascriptSerializer());
generator.Script += Console.Write; // bind to console output here
var queryProvider = new SampleQueryProvider
{
{
1, // user with id 1
new List<IQuery>
{
new ReplaceQuery("<name>", "frenchie"),
new GreetingToQuery("bonjour", "the universe"),
new LineEndingQuery()
}
},
{
2, // user with id 2
new List<IQuery>
{
new ReplaceQuery("<name>", "stegi"),
new GreetingToQuery("hello", "the world"),
new LineEndingQuery()
}
}
};
var data1 = new Data {Content = "My name is <name>."};
var data2 = new Data {Content = "I say hello to "};
var data3 = new Data {Content = "I say bonjour to "};
var data4 = new Data {Content = "."};
// you cold combine data and user query execution into lists and loops, too
generator.Generate(data1, queryProvider.GetQuerysForUser(1));
generator.Generate(data2, queryProvider.GetQuerysForUser(1));
generator.Generate(data3, queryProvider.GetQuerysForUser(1));
generator.Generate(data4, queryProvider.GetQuerysForUser(1));
generator.Generate(data1, queryProvider.GetQuerysForUser(2));
generator.Generate(data2, queryProvider.GetQuerysForUser(2));
generator.Generate(data3, queryProvider.GetQuerysForUser(2));
generator.Generate(data4, queryProvider.GetQuerysForUser(2));
Console.ReadKey();
}
}
你應該看到:
My name is frenchie.
I say bonjour to the universe.
My name is stegi.
I say hello to the world.
作爲你的功課......嘗試添加您自己的查詢實現和數據進行處理。你如何在這裏添加遞歸? ;-)
爲什麼選擇投票?我確定這是一個非常常見的重構情況。 – frenchie 2012-01-28 13:50:39
@Stegi:我該怎麼做? – frenchie 2012-01-28 14:06:15
您應該分離數據,查詢和處理(查詢執行和序列化)。我建議閱讀關於設計模式,控制反轉(IoC)和關注點分離的書籍/教程。請參閱http://www.dofactory.com/Patterns/Patterns.aspx – Beachwalker 2012-01-28 14:10:54