2016年5月18日 星期三

[Domain Driven Design] Use delegate for decoupling

 Driven Design    Design Pattern    Decoupling


Introduction


In this article, I will show how to use delegate to decouple the application and domain layers in DDD (Domain Driven Design).

The situation in this sample is that we want to make the Domain layer independent with other functions on the application layer which have the Data Access methods inside. In other words, the Domain layer should relies on virtual class but not real entities. Thus it can focus on the logic and algorithm in DDD.






Background


Refer to the activity diagram in the following picture. We will insert/update a data in to database. However, there are some business logics inside the insert or update methods. We want to pull the logics and flows out to the Domain, but what left in the Application are only the real insert/update database methods.

We will create the delegates in the logics class of Domain, and then inject the methods of Application into the delegates of logics class.

So the logics class only know the virtual (delegate), but it doesn’t know how and who would implement the virtual (real action).




Environment

l   Visual Studio 2015 Ent.



Implement



Architecture

 


Domain : Interface

// Query delegate
public delegate Profile QueryProfileHandler(string name);
// Insert delegate
public delegate void InsertProfileHandler(Profile profile);
// Update delegate
public delegate void UpdateProfileHandler(Profile profile);

public interface ISaveProfileStrategy
{
        void Merge<T>(T profile) where T : Profile;

        // Event for querying
        event QueryProfileHandler QueryProfile;
        // Event for inserting BlsDeliveryOrders
        event InsertProfileHandler InsertProfile;
        // Event for updating BlsDeliveryOrder
        event UpdateProfileHandler UpdateProfile;
}


Domain : Save Profile Strategy

l   For new profile

public class NewProfileStrategy : ISaveProfileStrategy
{
        public event InsertProfileHandler InsertProfile;
        public event QueryProfileHandler QueryProfile;
        public event UpdateProfileHandler UpdateProfile;

        public void Merge<T>(T profile) where T : Profile
        {
            //HACK : Some logics here ....
            Console.WriteLine("Domain : running some logics in NewProfileStrategy.");

            //Call the delegate
            this.UpdateProfile(profile);
        }
}


l   For exist profile

public class UpdateProfileStrategy : ISaveProfileStrategy
{
        public event InsertProfileHandler InsertProfile;
        public event QueryProfileHandler QueryProfile;
        public event UpdateProfileHandler UpdateProfile;

        public void Merge<T>(T profile) where T : Profile
        {
            //HACK : Some logics here ....
            Console.WriteLine("Domain : running some logics in UpdateProfileStrategy.");

            //Call the delegate
            this.InsertProfile(profile);
        }
}

Ok, now the Domain class relies on the delegate, it is isolated from other layers.


Application : The methods for delegates


public class ProfileDataAccessProvider
{
        public static Profile QueryProfile(string name)
        {
            //HACK : Call the DataAccess method to insert the poco ...
            Console.WriteLine("Application : query the data!");

            return new Profile() { Name = name };
        }

        public static void InsertProfile(Profile profile)
        {
            //HACK : Call the DataAccess method to insert the poco ...
            Console.WriteLine("Application : insert the data!");
        }

        public static void UpdateProfile(Profile profile)
        {
            //HACK : Call the DataAccess method to insert the poco ...
            Console.WriteLine("Application : update the data!");
        }
}


Presentation

Now inject the Service : provider into Domain, now we successfully decouple the Application and Domain layers.

List<Profile> profiles = new List<Profile>() {
                new Profile() {  Name = "JB" },
                new Profile() {  Name = "Lily" }
            };

foreach (var profile in profiles)
{
                ISaveProfileStrategy stg = null;

                //Inject the implement class to interface
                if (profile.Name.Equals("JB"))
                {
                    stg = new UpdateProfileStrategy();
                }
                else
                {
                    stg = new NewProfileStrategy();
                }

                //Inject the methods to delegates
                stg.InsertProfile += ProfileDataAccessProvider.InsertProfile;
                stg.UpdateProfile += ProfileDataAccessProvider.UpdateProfile;
                stg.QueryProfile += ProfileDataAccessProvider.QueryProfile;
               
                //Do the action
                stg.Merge(profile);
               
                //GC
                stg = null;
}


Result

 

Reference




沒有留言:

張貼留言