Interfaces and more
Summary:
If you want common behavior, you need an interface. And from the first one is a small step to re-organizing the program.
Body:
When you make a component for other people, you must make the possibility for those to
1. customize your software with their software
2. provide a default implementation
For the messaging component, the first customization is to provide a way for the site using the messaging to use their users.
The first step is to create a custom project which can provide guidance to the users that want to implement. VS provides XML documentation –I have checked and put also “warnings as error”
Next , I have create the User interface:
/// <summary> /// the user that can send messages /// TODO version 2: make pagination /// </summary> /// <typeparam name="UserPrimaryKey">the type of primary key</typeparam> public interface IUser<UserPrimaryKey> { /// <summary> /// the user primary key /// </summary> UserPrimaryKey Key { get; set; } /// <summary> /// the user name to be displayed /// </summary> string UserNameToDisplay { get; set; } /// <summary> /// other info for the user /// </summary> string OtherInfo { get; set; } /// <summary> /// find friends /// </summary> /// <param name="search">find user by name</param> /// <returns></returns> IEnumerable<KVPNew<UserPrimaryKey, string>> FindFriends(string search); /// <summary> /// find friends online /// </summary> /// <param name="search"></param> /// <returns></returns> IEnumerable<KVPNew<UserPrimaryKey, string>> FindFriendsOnline(string search); /// <summary> /// sends a message /// </summary> /// <param name="message"></param> void SendMessage(IUserMessage<IUser<UserPrimaryKey>, UserPrimaryKey> message); }
Two methods are interesting : SendMessage and FindFriends
Let’s take first SendMessage. It was obviously clear that I need another interface – the message to be sent. So the next interface created:
/// <summary> /// the message to be sent to the user /// TODO version 2: allow messaging for more than 1 user /// TODO version 2: message importance /// </summary> /// <typeparam name="TheUser">user interface</typeparam> /// /// <typeparam name="UserPrimaryKey">user primary key</typeparam> public interface IUserMessage<TheUser, UserPrimaryKey> where TheUser : IUser<UserPrimaryKey> { /// <summary> /// subject of the message /// </summary> string Subject { get; set; } /// <summary> /// body of the message /// </summary> string Body { get; set; } /// <summary> /// to the user /// </summary> TheUser To { get; set; } /// <summary> /// from the user /// </summary> TheUser From { get; set; } /// <summary> /// cc - as in email /// </summary> TheUser CC { get; set; } /// <summary> /// date of message /// </summary> DateTime DateInserted { get; set; } /// <summary> /// if recipient have read /// </summary> bool MessageRead { get; set; } // <summary> // bcc - as in email // </summary> //TheUser BCC { get; set; } }
Let’s take the other : IEnumerable<KVPNew<UserPrimaryKey, string>> FindFriends(string search);
It is clear that a user can send emails to friends( maybe to anybody if we make an intranet site for an enterprise) and I must somehow have the names and id’s of the friends. I could use KeyValuePair – but it is a struct and can not be compared with null . More, usually I need more data to be transferred – so I have created long ago a KVPNew class:
/// <summary> /// this is the correspondent class of KeyValuePair structure from .net /// The features: /// 1. it is a class- can be compared fastly with null /// 2. can be used in a search and display <paramref name="AdditionalData">AdditionalData </paramref> /// </summary> /// <typeparam name="TKEY">Key - it is compared in equals and GetHashCode</typeparam> /// <typeparam name="TValue">Value to be displayed</typeparam> public class KVPNew<TKEY, TValue> { public KVPNew() { } public KVPNew(TKEY key, TValue value):this() { this.Key = key; this.Value = value; } public TKEY Key { get; set; } public TValue Value { get; set; } public string AdditionalData { get; set; } public override bool Equals(object obj) { if (obj == null) return false; var o = obj as KVPNew<TKEY, TValue>; if (o == null) return false; return this.Key.Equals(o.Key); } public override int GetHashCode() { return this.Key.GetHashCode(); } }
And, being to interfaces, I have created also an interface for admin people to find users
/// <summary>
/// used by application to load plugins to find users
/// because each application can have it’s own way to find users
/// <summary> /// used by application to load plugins to find users /// because each application can have it's own way to find users /// used by admins to find users /// Improvement version 2 : pagination /// </summary> /// <typeparam name="T">user </typeparam> /// <typeparam name="UserKey">user key </typeparam> public interface IUsersFind<T,UserKey> where T:IUser<UserKey> { /// <summary> /// used to find users online to send message /// </summary> /// <param name="UserThatMakesTheSearch"> the user that makes the search </param> /// <param name="Search">search string - could be null</param> /// <returns> a list of users</returns> IEnumerable<KVPNew<T, string>> FindUsersOnline(T UserThatMakesTheSearch, string Search); /// <summary> /// used to find users (online or not )to send message /// </summary> /// <param name="UserThatMakesTheSearch"> the user that makes the search </param> /// <param name="Search">search string - could be null</param> /// <returns> a list of users</returns> IEnumerable<KVPNew<T, string>> FindUsers(T UserThatMakesTheSearch, string Search); /// <summary> /// find a user by his key /// </summary> /// <param name="key">the user key</param> /// <returns></returns> IUser<UserKey> FindUser(UserKey key); } /// <summary> /// operations with the database /// </summary> /// <typeparam name="User"></typeparam> /// <typeparam name="UserPrimaryKey"></typeparam> public interface IUserList<User, UserPrimaryKey>: IDisposable where User : IUser<UserPrimaryKey> { /// <summary> /// fast delete all from database - good for testing /// </summary> void FastDeleteAll(); /// <summary> /// add to internal list /// </summary> /// <param name="u">the user to be added </param> void Add(User u); /// <summary> /// save changes for new and old members /// </summary> void SaveNew(); /// <summary> /// save changes for old members /// </summary> void SaveExisting(); /// <summary> /// for retrieving /// </summary> /// <param name="i"></param> /// <returns></returns> User Find(int i); }
The final interfaces are in this picture:
Next time we will create the database EF4.1 files from DatabaseFirst and we will modify .tt templates to behave nicely with relationships.
Homework:
- Add to IUserMessage a BCC field
- What if To from IUserMessage will be directed to more than one person ?How do you implement it?
- Do you think that is something missed from KVPNew class?( Hint == operator and GetHashCode)
Hi can u please share me updated code if available