Reputation: 51927
I created a class that's called UserSessionModel; in it I'm storing some data about the user and in particular I'm storing several json strings that are the results of queries and serializations.
I have several methods and properties in UserSessionModel that overall look like this:
public string SomeUserDataInJson1 { get; set; }
public string SomeUserDataInJson2 { get; set; }
.... 3 more properties like this
public int UserID { get; set; }
private void GetSomeUserDataInJson1
{
ObjectData1 TheObjectData1 = new ObjectData1();
UserQueries TheUserQueries = new UserQueries();
JavascriptSerializer TheSerializer = new JavascriptSerializer();
TheObjectData1 = TheUserQueries.GetData1(TheUserID);
this.SomeUserData1InJson = TheSerializer.Serialize(TheObjectData1);
}
This code is repeated 5 times, with the only change being the ObjectData, the name of the query and the property SomeUserData that's getting set.
Is there a way to make this "better" with an interface or some other c# tools?
Thanks.
Upvotes: 1
Views: 180
Reputation: 7915
Ok, lets assume the following regarding to your example: You're having data for processing with queries defined differently per user (userId).
Our data container class... very simple here, contains only a string.
public class Data
{
public string Content { get; set; }
}
Next step, lets have a look at the query... could be using that interface (could use events, for the response but lets keep it simple here).
public interface IQuery
{
Data Process(Data data);
}
You could have a relation to the user by adding the userId to the IQuery interface but I would prefer to have another interface to solve that:
public interface IUserQueryProvider
{
IEnumerable<IQuery> GetQuerysForUser(uint id);
}
This way you can alter your user to query resolving in a seperate place.
You'll have a serializer/converter, too. Ok, lets make an Interface here for serialization of (processed) data.
public interface ISerializer
{
string Serialize(Data data);
}
Now, lets have a look at implementations, first of all the serializer... doesn't do anything magical here and you should fill in the things you need for serialization of objects (JSON, ...)
public class JavascriptSerializer : ISerializer
{
public string Serialize(Data data)
{
return data.Content; //whatever you want do instead for serialization
}
}
Now let us go to our Queries. I assume you're not very familiar with design patterns and you're meaning something like a Command Pattern instead (for processing jobs, see my link in the comments for more info about design pattern). 3 implementations follows as samples:
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;
}
}
If we want to resolve which querys belongs to a user we need our IUserQueryProvider implementation. It is nothing more than a dictionary in this case (but could be easyly switched to other implementations).
public class SampleQueryProvider : Dictionary<uint, IEnumerable<IQuery>>, IUserQueryProvider
{
public IEnumerable<IQuery> GetQuerysForUser(uint id)
{
IEnumerable<IQuery> queries;
TryGetValue(id, out queries);
return queries;
}
}
Last but not least... the glue for everything. I added another Interface here for our "generator engine".
public interface IScriptGenerator
{
event Action<string> Script;
void Generate(Data data, IEnumerable<IQuery> queries);
}
To make it more flexible I made the interface/implementation following a design principle introduced by Ralf Westphal called Event Based Components (EBC). Google is your friend if you are interested in this topic.
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);
}
}
And now lets put it all together and let us fly:
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();
}
}
You should see something like:
My name is frenchie. I say bonjour to the universe. My name is stegi. I say hello to the world.
As your homework... try to add your own query implementation and data to process. How would you add recursion here? ;-)
Upvotes: 2
Reputation: 4708
Firstly you should definitely use a List<string>
or string[]
. Then you can increase code space, and extensibility. You can loop through and load data into the list like your doing there. Another thing, did you mean TheQueries
by TheUserQueries
, as I can't see the latter declared or the former used.
If you ever find yourself creating more than two similar property like you have done, you should probably use a List
.
Secondly, the point of an interface is to force an object to implement certain methods etc. that can then be called and accessed in other classes. If that will help you, then you can put your method in an interface. Otherwise there's really no point.
Upvotes: 0