2010-01-17

Introduction to Composite Pattern

-->
Design patterns, CAB & SCSF

Hai phần trước đã nói sơ qua về CAB. Nhưng thật sự thì chưa có gì đọng lại ngoài những cái tên. Tiếp theo chúng ta sẽ điểm qua các Design patterns sử dụng trong CAB và SCSF. Các design patterns không thể liệt kê hết trong phần này mà cần tham khảo trong suốt những phần tiếp theo. Nếu một pattern được sử dụng trong CAB và SCSF cần tham khảo để tiếp tục thì mình sẽ bổ sung. Có thể tham khảo các design patterns tại http://www.dofactory.com/Patterns/Patterns.aspx
Giới thiệu Composite Pattern
 Đầu tiên sẽ đề cập đến design pattern cơ bản là Composite. Có thể tham khảo bài viết tại http://sourcemaking.com/design_patterns/composite.

Composite UML class diagram (sử dụng abstract class)

Composite UML class diagram (sử dụng interface)

Trong UML class diagram có thể thấy 3 phần chính
- Leaf là các đối tượng thành phần (hay còn gọi là Primitive).

- Component là giao diện cho các đối tượng thành phần, khai báo các method căn bản, là giao diện dùng khi access các thành phần.

- Composite định nghĩa các thao tác trên đối tượng thành phần, thực hiện lưu trữ và quản lý các đối tương thành phần.

Composite Pattern cho phép nhóm các object thành một single instance của một object. Các objects được nhóm có tính năng khá tương tự nhau. Object kết quả gọi là composite object. Việc thêm một component vào composite được hình dung tương tự việc thêm vào tree. Về kỹ thuật tất cả các Design patterns đều xoay quanh những tính năng của OOP encapsulation, inheritance, polymorphism...

Trong Composite kỹ thuật chính là polymorphism với 2 cách implement là polymorphism thông qua interface (recommended) và polymorphism qua abstract class.

Lab dành cho Composite Pattern

Ví dụ đơn giản khi có các region:
(England: (London: Chelsea)) và (France: Paris) nhóm thành Europe, một region lớn hơn như sau:

(Europe: (England: (London: Chelsea)) (France: Paris))

-->
Source code với C# (thực hiện qua interface)
Component.cs
-->

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Component interface
    /// </summary>
    interface Component
    {

        /// <summary>
        ///     Get the string of component (demo for component operation)
        /// </summary>
        ///
        ///     String of component
        /// </returns>
        string operation();

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        List<Component> getChildren();

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        void add(Component c);

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        bool remove(Component c);
    }
}

Composite.cs
using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Composite
    /// </summary>
    class Composite : Component
    {

        /// <summary>
        ///     ID
        /// </summary>
        private string _id;

        /// <summary>
        ///     Children collection
        /// </summary>
        private List<Component> _components = new List<Component>();

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///    
        /// </param>
        public Composite(string id)
        {
            _id = id;
        }

        #region [ INTERFACE IMPLEMENTATION ]

        /// <summary>
        ///     Operation
        /// </summary>
        /// <returns>
        ///     A string value present name and list of children recursive
        /// </returns>
        public string operation()
        {
            string s = " (" + _id + ":";
            this.getChildren().ForEach
            (
                delegate(Component child)
                {
                    s += " " + child.operation();
                }
            );

            return s + ") ";
        }

        /// <summary>
        ///     Implement interface get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        public List<Component> getChildren()
        {
            return _components;
        }

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public void add(Component c)
        {
            _components.Add(c);
        }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public bool remove(Component c)
        {
            return _components.Remove(c);
        }

        #endregion

    }
}

Leaf.cs
-->

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Leaf
    /// </summary>
    class Leaf : Component
    {

        /// <summary>
        ///    
        /// </summary>
        private string _id;

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///     ID
        /// </param>
        public Leaf(string id)
        {
            _id = id;
        }

        #region [ INTERFACE IMPLEMENTATION ]

        /// <summary>
        ///    
        /// </summary>
        /// <returns>
        ///     A string value...
        /// </returns>
        public string operation()
        {
            return _id;
        }

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     Just return null
        /// </returns>
        public List<Component> getChildren()
        {
            return null;
        }

        /// <summary>
        ///     Add to children collection, do nothing
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public void add(Component c) { }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     Just return false
        /// </returns>
        public bool remove(Component c) { return false; }

        #endregion

    }
}



Program.cs
-->
using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Program
    /// </summary>
    class Program
    {

        /// <summary>
        ///     Main entry point
        /// </summary>
        /// <param name="args" type="string[]">
        ///    
        /// </param>
        static void Main(string[] args)
        {

            // England
            Composite england = new Composite("England");

            // London
            Composite london = new Composite("London");
            london.add(new Leaf("Chelsea"));
            england.add(london);

            // Manchester
            Leaf manchester = new Leaf("Manchester");
            england.add(manchester);
            england.remove(manchester);

            // France
            Composite france = new Composite("France");
            france.add(new Leaf("Paris"));

            // Europe
            Composite europe = new Composite("Europe");
            europe.add(england);
            europe.add(france);

            // Get Europe
            Console.WriteLine(europe.operation());
            Console.ReadKey();
        }
    }
}

Source code với C# (thực hiện qua abstract class)
Component.cs
-->

using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Component interface
    /// </summary>
    public abstract class Component
    {

        /// <summary>
        ///     ID
        /// </summary>
        protected string _id;

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///    
        /// </param>
        public Component(string id)
        {
            _id = id;
        }

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        public abstract List<Component> getChildren();

        /// <summary>
        ///     Get the string of component (demo for component operation)
        /// </summary>
        /// <returns>
        ///     String of component
        /// </returns>
        public abstract string operation();

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public abstract void add(Component c);

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public abstract bool remove(Component c);
    }
}


Composite.cs
-->
using System;
using System.Collections.Generic;
using System.Text;

namespace DesignPatterns
{

    /// <summary>
    ///     Composite
    /// </summary>
    class Composite : Component
    {

        /// <summary>
        ///     Children collection
        /// </summary>
        private List<Component> _components = new List<Component>();

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///    
        /// </param>
        public Composite(string id)
            : base(id)
        { }

        #region [ OVERRIDE METHODS ]

        /// <summary>
        ///     Operation
        /// </summary>
        /// <returns>
        ///     A string value present name and list of children recursive
        /// </returns>
        public override string operation()
        {
            string s = " (" + _id + ":";
            this.getChildren().ForEach(delegate(Component child) { s += " " + child.operation(); });
            return s + ") ";
        }

        /// <summary>
        ///     Implement interface get all children
        /// </summary>
        /// <returns>
        ///     List of <see cref="Component"/> children
        /// </returns>
        public override List<Component> getChildren()
        {
            return _components;
        }

        /// <summary>
        ///     Add to children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public override void add(Component c)
        {
            _components.Add(c);
        }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     A bool value...
        /// </returns>
        public override bool remove(Component c)
        {
            return _components.Remove(c);
        }

        #endregion

    }
}

Leaf.cs
-->
using System;
using System.Collections.Generic;
using System.Text;


namespace DesignPatterns
{

    /// <summary>
    ///     Leaf
    /// </summary>
    class Leaf : Component
    {

        /// <summary>
        ///     Constructor
        /// </summary>
        /// <param name="id" type="string">
        ///     ID
        /// </param>
        public Leaf(string id) : base(id) { }

        #region [ OVERRIDE METHODS ]

        /// <summary>
        ///    
        /// </summary>
        /// <returns>
        ///     A string value...
        /// </returns>
        public override string operation()
        {
            return _id;
        }

        /// <summary>
        ///     Get all children
        /// </summary>
        /// <returns>
        ///     Just return null
        /// </returns>
        public override List<Component> getChildren()
        {
            return null;
        }

        /// <summary>
        ///     Add to children collection, do nothing
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to add
        /// </param>
        public override void add(Component c) { }

        /// <summary>
        ///     Remove from children collection
        /// </summary>
        /// <param name="c" type="Component">
        ///     Child <see cref="Component"/> to remove
        /// </param>
        /// <returns>
        ///     Just return false
        /// </returns>
        public override bool remove(Component c) { return false; }

        #endregion

    }
}

Qua bài này chúng ta sẽ chính thức tìm hiểu CAB. Part tiếp theo sẽ là part đầu tiên và mình sẽ đánh số cho dễ theo dõi bắt đầu là Part 1.

Design patterns, CAB & SCSF

Design patterns, CAB & SCSF

Mục đích phần này
- Tìm hiểu khái quát các design patterns được sử dụng, hiểu cấu trúc căn bản của CAB.
- Tìm hiểu khái quát SCSF (Smart Client Software Factory).

Khái quát về CAB
Thiết kế của CAB dựa trên 3 điểm chính như sau:
- Thực hiện tìm và loading các modules tại thời điểm khởi tạo ứng dụng để thực hiện build tự động solution.
- Tách biệt việc develop UI và shell khỏi việc develop business logic.
- Đạt được khả năng tái sử dụng và module hóa code bằng cách cung cấp các kỹ thuật “liên kết yếu” (loosely coupled)

Subsytems của CAB
Tìm và load modules
Mục tiêu chính của CAB là hỗ trợ việc phát triển ứng dụng từ nhưng module độc lập nhưng lại có thể liên kết với nhau. Mục tiêu này có thể đạt được nhờ những điểm sau:
- Implement một catalog, catalog này mô tả và chỉ định modules nào sẽ được load.
- Một module loader thực hiện load và initialize các module có trong application.

Việc implement này có thể customize nhưng không cần chỉnh sửa core implementation của CAB (các subsystems của CAB đề hoạt động như các plug-ins). Ví dụ có thể load danh sách các modules từ web service vào ứng dụng thay vì đọc danh sách từ file.

User Interface và Shell
Thông thường để developer có kiến thức sâu business logic được yêu cầu và có cả kỹ thuật tốt trong việc phát triển UI và Shell là không đơn giản. Trong những dự án có khối lượng công việc lớn để đảm bảo tính nhất quán và khả năng phát triển nhanh chóng (productivity, consistency) cần phát triển các resuable components bao hàm cả bussiness logic. CAB cung cấp các kiến trúc và kỹ thuật quanh việc tạo các component dựa trên Windows Forms bao gồm:
- Một cách nhất quán để show và hide controls sử dụng Workspaces. Một shell developer tạo visual effects, layout strategies hay các behaviors khác nhưng không ảnh hưởng business logic component.
- Một cách chung để thêm và sử dụng một UIElement vào shell như menu items, status bars một cách dễ dàng mà không cần phải quá quan tâm làm cách nào để cách thành phần đó có thể hiển thị tại vị trí cần thiết...
- Một kiến trúc Command cho phép business logic developer có thể định nghĩa các action mà user có thể thực hiện và cách mà những action này sẽ hiển thị trên một shell cụ thể.

Khả năng thiết kế các business logic thành những module
Các tính năng cho phép thực hiện các module với “liên kết yếu”
- WorkItems cung cấp một cách thực hiện phạm vi hóa dễ dàng các components tham gia chung 1 trường hợp sử dụng (use case), chia xẻ chung trạng thái (share state), events và các common services.
- EventBroker cung cấp một cơ chế “liên kết yếu” bằng event many-to-many (many-to-many, loosely coupled event system mechanism between objects) giữa các objects trong ứng dụng.
- Chia xẻ trạng thái bằng State cho phép các component có thể lưu trữ và lấy thông tin.

Các tính năng chính khác
- Thực hiện loading tự động cách modules độc lập vào một common shell.
- Dùng Event Broker để tạo một giao tiếp “liên kết yếu” (loosely coupled communication) giữa các modules và giữa các parts của module.
- Sử dụng và implement sẵn Command Pattern
- Implement sẵn các base classes theo MVC (Model-View-Control) pattern.
- Tạo framework cho các pluggable infrastructure services như authentication services, authorization services, module location, và module loding service.

CAB-SCSF: Làm quen với Composite UI Application Block

Phần này dựa trên các document cũ mà mình đã viết chủ yếu focus .NET Framework 2.0 và Visual Studio 2005

-->
Dựa trên series của Rich

Mục đích chung
- Tự xác định lại khả năng và hiểu biết về develop software nói chung và develop với công nghệ Microsoft.
- Nâng cao khả năng develop trên nền Microsoft .NET Framework và các khái niệm của software development. Tiếp cận với các khái niệm cần thiết trong quá trình phát triển software chuyên nghiệp.
- Xác định yêu cầu self-training và tham khảo materials là cần thiết với developer.

CAB-SCSF - Composite UI Application Block & Smart Client Software Factory

Các resources về CAB-SCSF:

Smart Client – Composite UI Application Block

Smart Client Software Factory

New Guidance and Tools for Building Integrated Desktop Applications

CAB viết tắt của Composite UI Application Block là một application block được phát triển bởi Microsoft trên nền Microsoft .NET Framework 2.0. CAB cung cấp các reusable source code dưới dạng các component dùng để tạo các complex smart client UI. Các components này được thiết kế theo các well-known design patterns như Composite, Command... Với thiết kế các UI part theo design patterns có thể dễ dàng tích hợp nhiều phần đơn giản để tạo các complex solutions trong khi giai đoạn phát triển có thể là độc lập (develop, test hay deploy).
 
Đối tượng có thể tìm hiểu: software architecturessoftware developers đã nắm vững các kỹ thuật trên nền tảng Microsft .NET Framework 2.0, nắm các kiến thức cần có về ngôn ngữ lập trình. Trong quá trình tìm hiểu nếu tự thấy không thể nắm bắt được những khái niệm hay hướng dẫn trong tài liệu này, yêu cầu tự tìm tài liệu nghiên cứu phần trước đó và những khái niệm bổ trợ.
 
Yêu cầu software và language:
- Language C#
- IDE: Visual Studio .NET 2005 Team hoặc 2008 Team
- NUnit hoặc test module trong IDE

Yêu cầu cài đặt chung:

UNnit

Enterprise Library for .NET Framework 2.0

Composite UI Application Block in C#

Guidance Automation Extensions

Guidance Automation Toolkit

Introduction to CAB-SCSF


Mặc dù CAB và SCSF đã ra từ lâu nhưng làm việc với nó cũng là một trải nghiệm thú vị. Hiện nay Microsoft đang khuyến khích dùng Windows Presentation Foundation (WPF) cho tương lai của Smart Client và từ từ rời bỏ WinForms application. Qua thời gian làm việc như một trainer trong in-house project mình hiểu thế nào là khó khăn mà junior developer gặp phải khi mới biết sơ sơ .NET đã phải làm quen với một application framework. Thời gian và pratice là 2 điều quan trọng nhất nhưng lại bị o ép bởi deadline cho dù mục tiêu khi nào cũng đặt ra là product và thòng thêm training. Và một khi project gặp khó khăn thì những người không biết gì sẽ quy kết cho junior developer là thiếu kinh nghiệm và khả năng học tập :(. Tất nhiên vị trí trainer cũng bị ảnh hưởng :P. Rảnh rỗi nên post về SCSF và hy vọng có thời gian để tiếp tục post về các framework đang dùng.



Phần lớn những gì viết ở đây được lấy từ series rất nổi tiếng của Rich Newman tại http://richnewman.wordpress.com/intro-to-cab-toc/. Một vài phần lấy từ blog MSDN và SCSF hand-on laps. Cá nhân mà nói thì các articles của Rich Newman tốt hơn cả guidance của Microsoft.


Về roadmap cho developer có thể tham khảo qua article trên C# corner 
http://www.c-sharpcorner.com/UploadFile/tjayram/DeveloperRoadmapForBuildingSmartClientApplications08062006192216PM/DeveloperRoadmapForBuildingSmartClientApplications.aspx

Thời gian hoàn thành theo roadmap thường đề cập là khoảng 5 năm trong khi mình cũng chỉ ra trường mới 5 năm :(. Nếu cứ theo như vậy thì công nghệ sắp tới sẽ bỏ ở đâu và tại Việt Nam công ty hay tổ chức nào thực sự muốn làm theo những công nghệ này. Code for fun ...