Showing posts with label UML. Show all posts
Showing posts with label UML. Show all posts

Wednesday, May 18, 2016

[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




Wednesday, July 8, 2015

從Class產生Class diagram(Astah Professional)

在"從Class產生Class diagram(Visual Studio Ultimate)"中,

有提到如何用Visual Studio產出Class diagram;

然而Visual Studio 2013目前提供的UML Tool和其他市面上的工具相比仍較陽春。
(期待 2015 有更強大的功能~~ )

目前小弟專案中拉UML比較常用到的是 Astah 這套工具 ,它也有提供將Class轉為Class diagram的Plug-in。

可是只限定在付費版本(Astah Professional)。

至於作法可參考這片文章說明。

從Class產生Class diagram(Visual Studio Ultimate)

 UML   Visual Studio 2013  

▌背景

到新環境上工第一天,馬上收到其中一項任務是用Visual Studio將Class轉換為Class diagram。 依稀記得書上有提到這個功能,但是實際上並沒有操作過,因此在這邊紀錄一下。
(其實在專案中,我們也很少畫Class diagram XD)

※特別需要注意的是,只有Visual Studio 2013 Ultimate版本才有提供UML Modeling的專案類型。

▌環境
l  Visual Studio 2013 Ultimate


▌步驟


l   在方案中加入一個「模型專案」,並新增一個「UML類別圖」。






開啟架構總管(Architecture Explorer, 熱鍵為Ctrl+\,Ctrl+R),找到要建立Class diagram的Class,如下圖的Todo。






l   拖曳該Class到Class diagram的空白區,將會自己建立好Cass diagram。
PS.
注意要從類型(Types)那一個區塊拖曳過去。


▌Reference




Sunday, June 24, 2012

[UML] Class Diagram for C#

[UML] Class Diagram for C#

This article is designing a Class Diagram for the ROLES Classes in a Star Wars game.
In this game, every person have his/her own role type which can be "Civilian", "Warrior", "Politician" ... etc.

The following claass diagram only shows how a "Warrior" use their weapons.


Picture 01 - The whole diagram



1. Realization

So I create a class named CWarrior, which implements the interface IWarrior.
The relation between them is Realization.
That means CWarrior implements IWarrior.
  (Picture 02 - Realization)
public class CWarrior : IWarrior
    {
        private CCamp myCamp; //陣營
        protected String myName; //名稱

        /* cCamp */
        public CCamp Camp
        {
            get
            {
                return myCamp;
            }
            set
            {
                myCamp = value;
            }
        }
        /* sName */
        public String Name
        {
            get
            {
                return myName;
            }
            set
            {
                myName = value;
            }
        }

        /* 使用武器 */
        public virtual void Use_Weapon()
        {
            Console.WriteLine("{0} 使用了武器。", myName);
        }
    }


2. Aggregation

We use a enum class named CCamp in CWarrior.

A warrior belongs to no or only one camp.
A camp can keep existing even when a warrior disappear.
So the relation between them is Aggregation.
 (Picture 03 - Aggregation)

public enum CCamp
    {
        Empire,
        Rebel_Alliance
    }




3. Generalization

Next step, we create two class CJedi and CSith , to generalize CWarrior.
We add an additional property : CWeapon Weapon (see 4.),
and a override method : Use_Weapon() to use Jedi's and Sith's special weapons.
The Generalization between a child class and a father class is showed in picture 04.
 (Picture 04 - Generaliztion )

public class CJedi : CWarrior
    {
        public CWeapon Weapon; //武器

        /* 使用武器 (改寫) */
        public override void Use_Weapon()
        {
            Console.WriteLine("絕地武士 {0} 使用了武器 - {1}。", this.myName, this.Weapon);
        }
    }

public class CSith : CWarrior
    {
        public CWeapon Weapon; //武器

        /* 使用武器 (改寫) */
        public override void Use_Weapon()
        {
            Console.WriteLine("西斯武士 {0} 使用了武器 - {1}。", this.myName, this.Weapon);
        }
    }



4. Composition

We use CWeapon in both CJedi and CSith.
In my opnion, the weapons cannot be used if the Jedi and Sith warriors all disappear.
So I use the Composition relation here.
That means CWeapon only exist or use with CJedi and CSith, other class can't use CWeapon.
Furthermore, one jedi/sith can only have one weapon, so the multiplicity is set to be 1 to 1.
 (Picture 05 - Composition)
 public enum CWeapon
    {
        Laser_Gun,
        Light_Saber
    }



Test result ...

A warrior named "白兵" used his weapon.
output  :  白兵 使用了武器。

A Jedi named "路克天行者" used his weapon.
output : 絕地武士 路克天行者 使用了武器 - Light_Saber。

A Sith named "達斯維達" used his weapon.
output : 西斯武士 達斯維達 使用了武器 - Light_Saber。



Reference :
http://www.webdsai.idv.tw/?p=2329