Windows Service State Publisher

Introduction

ServiceStatePublisher extends the .NET System.ServiceProcess library. The ServiceStatePublisherlibrary introduces the ability to observe or listen for state changes to a Windows Service.

Why create this library extension? To get experience using several design patterns. In particular, this project will incorporate 3 design patterns:

  1. Singleton
  2. State
  3. Observer/Publish-Subscribe

Having been a casual observer of this site for awhile, I know the design patterns topic is one of those religious hotbeds. For me, they represent a nice way to communicate what you’re doing — and if by chance someone recognizes the design pattern…you know, “hey, that’s the fuzzy duck pattern“…then all the better. I don’t take it as criticism or superiority, but rather as a compliment. The observer was excited to recognize something they learned can be used in practice. And, the code was clear enough for them to see the forest through the trees (i.e. beneath the surface of the code). Hopefully, this code will be clear enough. Wink | ;-)

To demonstrate the use of this library, I have constructed the Oracle Service Manager application, found elsewhere on this site. Oracle Service Manager mimics the Microsoft SQL Server Service Manager.

Background

I have listed the references, at the end of this article, from which I derived my work; however, there are many articles on this site, and the Internet, that are excellent sources for the topics covered. Topics covered include the designpatterns identified above as well as .NET Framework topics such as the System.ServiceProcess .NET namespace, delegates, and events.

Problem Analysis

Windows Services are not designed to fire events alerting observers when a service has changed state. This library extension provides a framework to add one or more service observers. For example, if you wanted to create a utility to monitor and control the Oracle Windows services – just like the SQL Server Service Manager – you would need 3 observers: a dialog observer, a tray icon observer, and a timer/polling observer. A change in the state of the server ought to be broadcasted to all listeners, so they can decide if there is any action to take – like updating a user interface.

I have created a project and wrote an article, found elsewhere on CodeProject, for just this purpose – monitoring and controlling Oracle services – it’s called Oracle Service Manager.

Using Design Patterns

There are two primary issues to solve. The first is the state of the service. The operations performed on a service (e.g. Start, Stop, Pause, and Continue) are dependent on the internal state of the service. In other words, a running service can be stopped and, possibly, paused; however it cannot be started or continued. Most of the time, this issue is solved with a big conditional statement. The State pattern puts each branch of the conditional statement in a separate class. [GHJV98]

The second issue concerns notifying interested parties of the change in state. When a running service stops, all parties interested in observing the service should be notified of the new state regardless of whether that party initiated the request. The Observer pattern allows us to notify other objects without making assumptions about who these objects are. In other words, you don’t want these objects tightly coupled. [GHJV98]

Gamma et al, classify both patterns as behavioral. In addition, the two patterns have a relationship to one another in this library. That is, examining the two patterns reveals, the observer pattern means nothing unless the state of a service changes. This implies that the observer pattern has a dependency on the state pattern. Therefore, the observer pattern implementation needs to subclass the state pattern implementation. In short, the observer subject will derive from, or extend, the state context class.

The state pattern declares each state be represented by a concrete class. This introduces a decision of when to allocate and clean up the concrete state objects. Since we are only interested in tracking one service at a time, and we have a limited number of concrete states, we can minimize memory allocations by creating all concrete state objects at startup. This introduces a requirement to ensure and manage a single instance. This problem is solved by a thirdpattern – the Singleton pattern [GHJV98].

Below, I discuss the characteristics of the design pattern implementations. If you are only interested in using this library, your interest will lie in one of two classes: the ServiceContext in the State pattern; or the ServiceSubjectin the Observer pattern.

State Pattern

Figure 1.  Diagram of State Pattern as illustrated in Design Patterns [GHJV98]

The State pattern diagrammed above outlines the participants needed to support the model. The equivalent types needed for the ServiceStatePublisher library are:

Context  ServiceContext.

  • Defines the interface of interest to clients. In other words, as a user of this pattern, this is the class to program against. This class exposes all supported behaviors and properties encapsulated by the ConcreteState classes.
  • Maintains an instance of a ConcreteState subclass that defines the current state
  • Context delegates state-specific requests to the current ConcreteState object†
  • Context passes itself as an argument to the State object handling the request. This lets the State object access the context†
  • Either Context or the ConcreteState subclasses can decide which state succeeds another and under what circumstances†
public class ServiceContext
{
    protected ServiceController _controller;
    protected ServiceState _state;

    public ServiceContext()
    {
        State = ServiceStateUnknown.Instance;
        Controller = null;
    }

    public void Start()
    {
        State.Start( this);
    }

    public void Stop()
    {
        State.Stop( this);
    }

    public void Pause()
    {
        State.Pause( this);
    }

    public void Continue()
    {
        State.Continue( this);
    }
}

State  ServiceState.

  • Defines an interface for encapsulating the behavior associated with a particular state of the Context
  • I did not implement this as an interface because the actual implementation has some important, but not obvious, default behavior. So, instead, I used a public abstract class to indicate this is a base class from which subclasses derive. More importantly, this class cannot be instantiated on its own. Indeed, this class is the base class for the ConcreteState classes discussed below.
  • As a base class, ServiceState is the natural place to put common error logging for each of the subclasses.
  • The important default behavior is the empty body for each virtual function. This means, by default, a call to a method that is not overridden will do nothing. This will ease the burden for each ConcreteState class.
public abstract class ServiceState
{
    public virtual void Start( ServiceContext context) { }
    public virtual void Start( ServiceContext context, string[] args) { }
    public virtual void Stop( ServiceContext context) { }
    public virtual void Pause( ServiceContext context) { }
    public virtual void Continue( ServiceContext context) { }

    …

    protected virtual void LogError( string message, EventLogEntryType entryType)
    {
        if (!EventLog.SourceExists( SSP_SOURCE))
            EventLog.CreateEventSource( SSP_SOURCE, SSP_EVENTLOG);

        EventLog sspLog = new EventLog();
        sspLog.Source = SSP_SOURCE;

        sspLog.WriteEntry( message, entryType);

        sspLog.Close();
    }
}
ConcreteStates ServiceRunningServiceStoppedServicePaused,
ServicePendingStartServicePendingStopServicePendingPause,
ServicePendingContinueServiceStateUnknown
  • Each subclass implements a behavior associated with a state of the Context
  • Each ConcreteState class is derived from ServiceState.
  • Each ConreteState has a one-to-one mapping with the ServiceControllerStatuses in .NET, with one exception.
  • Included is a class to reflect an unknown state, such as when a server or service has not been selected.
  • Because the base class, ServiceState, implements a default behavior, only those methods requiring overrides must be implemented. In other words, the ServiceRunning state need only override the methods that are allowable in that state – Stop() and Pause(). If the client program calls Start() or Continue() when thestate is ServiceRunning, the default behavior is executed – do nothing. This treatment means we do not need to explicitly check for invalid requests, because the invalid request will be dealt with gracefully without error.
public class ServiceRunning : ServiceState
{
    …

    public override void Stop( ServiceContext context)
    {
        try
        {
            context.Controller.Stop();
            context.Controller.WaitForStatus( 
                ServiceControllerStatus.Stopped, new TimeSpan(0,0,30));
            ChangeState( context, ServiceStopped.Instance);
        }
        catch (TimeoutException te)
        {
            LogError( te.Message, EventLogEntryType.Warning);
            throw;
        }
    }

    public override void Pause( ServiceContext context)
    {
        try
            {
            context.Controller.Pause();
            context.Controller.WaitForStatus( 
                ServiceControllerStatus.Paused, new TimeSpan(0,0,30));
            ChangeState( context, ServicePaused.Instance);
        }
        catch (TimeoutException te)
        {
            LogError( te.Message, EventLogEntryType.Warning);
            throw;
        }
    }
}

Observer Pattern

Figure 2.  Diagram of Observer Pattern as illustrated in Design Patterns [GHJV98]

The Observer pattern diagrammed above outlines the participants needed to support the model. The Observerpattern is also known as: Listener and Publish-and-Subscribe. One noteworthy item is how well .NET provides native support for this pattern through built-in functionality found in delegates and events. The equivalent types needed for the ServiceStatePublisher library are:

Subject  Not applicable.

  • Knows its observers. Any number of Observer objects may observe a subject
  • Provides an interface for attaching and detaching Observer objects§ (e.g., in C#, the syntax to attach isobject.event += new EventHandler(); to detach, C# uses the -= operator)
  • .NET provides this functionality through its built-in support of delegates and events
  • The ConcreteSubject establishes this contract through .NET’s event support – see below.

ConcreteSubject ServiceSubject.

  • This is the publisher and defines the interface of interest to clients’. In other words, if you want published events, this is the class you should use, or program against, in your application.
  • Stores state of interest to ConcreteObserver objects§
  • Sends a notification to its observers when its state changes§ (i.e., publishes the event to subscribers)
  • .NET supports this functionality through its built-in support of delegates and events
public class ServiceSubject : ServiceContext
{
    public event EventHandler ServerChanged;
    public event EventHandler ServiceChanged;
    public event EventHandler StateChanged;

    protected string _serverName;

    public ServiceSubject() : base() { }

    public ServiceSubject( ServiceController service)
    {
        Controller = service;
    }

    public virtual string ServerName
    {
        get { return _serverName; }
        set
        {
            _serverName = value;
            OnServerChanged( EventArgs.Empty);
            if (Controller != null && _serverName != Controller.MachineName)
                Controller = null;
        }
    }

    public override ServiceController Controller
    {
        get { return _controller; }
        set
        {
            _controller = value;
            _state = QueryServiceState();
            OnServiceChanged( EventArgs.Empty);
        }
    }

    public override ServiceState State
    {
        get { return _state; }
        set
        {
            _state = value;
            OnStateChanged( EventArgs.Empty);
        }
    }

    public virtual void RefreshServices()
    {
        OnServerChanged( EventArgs.Empty);
    }

    protected virtual void OnServerChanged( System.EventArgs e)
    {
        if (ServerChanged != null)
            ServerChanged( this, e);
    }

    protected virtual void OnServiceChanged( System.EventArgs e)
    {
        if (ServiceChanged != null)
            ServiceChanged( this, e);
    }

    protected virtual void OnStateChanged( System.EventArgs e)
    {
        if (StateChanged != null)
            StateChanged( this, e);
    }
}

Observer Not applicable.

  • Defines an updating interface for objects that should be notified of changes in a subject§
  • .NET provides this functionality through its built-in support of delegates and events

ConcreteObservers Implemented in client application.

  • This is the actual subscriber or listener
  • Maintains a reference to a ConcreteSubject object§
  • Stores state that should stay consistent with the subject’s§
  • Implements the Observer updating interface to keep its state consistent with the subject’s§
  • .NET provides this functionality through its built-in support of delegates and events
  • The observers are implemented in the client application. I created an example, Oracle Service Manager, for some “real” world applicability.
using System;
using System.ServiceProcess;
using kae.ServiceStatePublisher;

public class SampleObserver
{
    public SampleObserver( ServiceSubject subject)
    {
        if (subject != null)
        {
            subject.ServerChanged += new EventHandler( this.OnServerChanged);
            subject.ServiceChanged += new EventHandler( this.OnServiceChanged);
            subject.StateChanged += new EventHandler( this.OnStateChanged);
        }
    }

    private void OnServerChanged( object sender, EventArgs e)
    {
        ServiceSubject subject = (ServiceSubject) sender;
        …
    }

    private void OnServiceChanged( object sender, EventArgs e)
    {
        ServiceSubject subject = (ServiceSubject) sender;
        …
    }

    private void OnStateChanged( object sender, EventArgs e)
    {
        ServiceSubject subject = (ServiceSubject) sender;
        …
    }
}

Singleton Pattern

Figure 3.  Diagram of Singleton Pattern as illustrated in Design Patterns [GHJV98]

The Singleton pattern diagrammed above outlines the sole participant needed to support the model. The Singletonpattern is applied differently depending on whether you need a single instance inside a single process or across multiple processes. In the latter case, an operating system level resource must be used. In the former case, a static constructor can be used to create the one and only instance.

Singleton ServiceRunningServiceStoppedServicePaused
ServicePendingStartServicePendingStopServicePendingPause
ServicePendingContinueServiceStateUnknown
  • Defines an Instance operation that lets clients access its unique instance. Instance is a class operation**
  • Responsible for creating its own unique instance**
  • In C#, we use a static property as the accessor
public class ServiceRunning : ServiceState
{
    private static ServiceRunning _instance;

    static ServiceRunning()
    {
        lock (typeof(ServiceRunning))
        {
            if (_instance == null)
                _instance = new ServiceRunning();
        }
    }

    public static ServiceRunning Instance
    {
        get { return _instance; }
    }

    …
}

Future Directions

As I have mentioned above, the ServiceStatePublisher library is used in a companion article, Oracle Service Manager, as an example application that may have some relevance to your development environment. In addition, using this library for a Visual Studio add-in to manage the Windows Services of any database (e.g., Oracle, DB2, MySQL, SQL Server, etc.) could be a nice alternative to the browsing mechanism offered by the Server Explorer in Visual Studio. Perhaps, there is also an enhancement to ensure changes in state happen in a worker thread, allowing the main thread to be more responsive to the interface.

LINK: http://www.codeproject.com/Articles/7043/Windows-Service-State-Publisher

Understanding and Implementing State Pattern in C#

There are times when we find some scenarios in our application when we need to maintain the state of a sub system. This state needs to be changed based on some conditions and/or user actions. One way to keep track of such states is by using the conditional logic in code.

Using conditional logic will get us the desired result but that would result in a code that is less understandable and is harder to maintain. Also, if we need to add more states in the system then that is very difficult and could create problems in existing system too.

To tackle such problems efficiently, GoF suggest use of State pattern. GoF defines state pattern as “Allow an object to alter its behavior when its internal state changes. The object will appear to change its class.

It can also be thought of as an object oriented state machine. Let us see the major classes in this pattern.

  • Context: This is the actual object who is accessed by the client. The state of this object needs to be tracked.
  • State: This is an interface or abstract class that defines the common behavior associated with all the possiblestates of the Context.
  • ConcreteState: This class represent a state of the Context. Each state will be represented as one concrete class.

Using the code

Let us try to implement a small example to understand the state pattern in detail. Let us try to implement the software for a dummy ATM machine. The ATM machine is with us and the Bank has decided to have 3 states for this machine.

  1. No card in the machine
  2. Card inserted and has been validated
  3. Cash withdrawn

Now first let us see how we would implement this solution without using the state pattern. We would create a class for the ATM and then have the state of the ATM maintained locally. Following code snippet shows how we could implement such ATM class and keep the state of the machine inside the object itself.

class NoStateATM
{
    public enum MACHINE_STATE
    {
        NO_CARD,
        CARD_VALIDATED,        
        CASH_WITHDRAWN,
    }

    private MACHINE_STATE currentState = MACHINE_STATE.NO_CARD;
    private int dummyCashPresent = 1000;

    public string GetNextScreen()
    {
        switch (currentState)
        {
            case MACHINE_STATE.NO_CARD:
                // Here we will get the pin validated
                return GetPinValidated();
                break;
            case MACHINE_STATE.CARD_VALIDATED:
                // Lets try to withdraw the money
                return WithdrawMoney();
                break;
            case MACHINE_STATE.CASH_WITHDRAWN:
                // Lets let the user go now
                return SayGoodBye();
                break;            
        }
        return string.Empty;
    }

    private string GetPinValidated()
    {
        Console.WriteLine("Please Enter your Pin");
        string userInput = Console.ReadLine();

        // lets check with the dummy pin
        if (userInput.Trim() == "1234")
        {
            currentState = MACHINE_STATE.CARD_VALIDATED;
            return "Enter the Amount to Withdraw";
        }
            
        // Show only message and no change in state
        return "Invalid PIN";
    }

    private string WithdrawMoney()
    {            
        string userInput = Console.ReadLine();

        int requestAmount;
        bool result = Int32.TryParse(userInput, out requestAmount);

        if (result == true)
        {
            if (dummyCashPresent < requestAmount)
            {
                // Show only message and no change in state
                return "Amount not present";
            }

            dummyCashPresent -= requestAmount;
            currentState = MACHINE_STATE.CASH_WITHDRAWN;

            return string.Format(@"Amount of {0} has been withdrawn. Press Enter to proceed", requestAmount);
        }

        // Show only message and no change in state
        return "Invalid Amount";
    }

    private string SayGoodBye()
    {
        currentState = MACHINE_STATE.NO_CARD;
        return string.Format("Thanks you for using us, Amount left in ATM: {0}", dummyCashPresent.ToString());
    }
}

Now when we run the class we can see that this works perfectly from the functionality perspective.

The problem will come when we need to add more states. Whenever we need to add more states to this ATM machine we need to open up the ATM machine code and then add more logic inside this class itself which is a clear violoation of Open-Close priciple. Also since we have all that state managed in form of conditional logic, there are some possibilities that changing code to add new states will break existing functionality too i.e. this way is more error prone.

So, what would be the better way to do this? The better way to do this is by implementing the same solution usingstate pattern. The only thing that we need to do is “encapsulate what varies”. So we will go ahead and pull the staterelated logic from the ATM class and create seprate classes for each state.

Let us start by modifying the ATM class so that it will contain no state related information. It will only keep an handle to the object which keeps track of its state.

public class ATM
{
    public ATMState currentState = null;        

    public ATM()
    {
        currentState = new NoCardState(1000, this);
    }

    public void StartTheATM()
    {
        while (true)
        {
            Console.WriteLine(currentState.GetNextScreen());
        }
    }
}

Now the member variable in this class that is being used as the handle to the state is just an abstract class. This class will point to the actual concrete implementation of state i.e. the real state of the machine dynamically.

public abstract class ATMState
{
    private ATM atm;

    public ATM Atm
    {
        get { return atm; }
        set { atm = value; }
    }
    private int dummyCashPresent = 1000;

    public int DummyCashPresent
    {
        get { return dummyCashPresent; }
        set { dummyCashPresent = value; }
    }

    public abstract string GetNextScreen();
}

And finally we have all the concrete classes, each for one state of the ATM machine. Lets look at all the state classes now

The class for NO_CARD state:

class NoCardState : ATMState
{
    // This constructor will create new state taking values from old state
    public NoCardState(ATMState state)     
        :this(state.DummyCashPresent, state.Atm)
    {
        
    }

    // this constructor will be used by the other one
    public NoCardState(int amountRemaining, ATM atmBeingUsed)
    {
        this.Atm = atmBeingUsed;
        this.DummyCashPresent = amountRemaining;
    }

    public override string GetNextScreen()
    {            
        Console.WriteLine("Please Enter your Pin");
        string userInput = Console.ReadLine();

        // lets check with the dummy pin
        if (userInput.Trim() == "1234")
        {
            UpdateState();
            return "Enter the Amount to Withdraw";
        }

        // Show only message and no change in state
        return "Invalid PIN";
    }

    private void UpdateState()
    {
        Atm.currentState = new CardValidatedState(this);
    }
}

The class for CARD_VALIDATED state:

class CardValidatedState : ATMState
{
    // This constructor will create new state taking values from old state
    public CardValidatedState(ATMState state)    
        :this(state.DummyCashPresent, state.Atm)
    {
        
    }

    // this constructor will be used by the other one
    public CardValidatedState(int amountRemaining, ATM atmBeingUsed)
    {
        this.Atm = atmBeingUsed;
        this.DummyCashPresent = amountRemaining;
    }

    public override string GetNextScreen()
    {
        string userInput = Console.ReadLine();

        int requestAmount;
        bool result = Int32.TryParse(userInput, out requestAmount);

        if (result == true)
        {
            if (this.DummyCashPresent < requestAmount)
            {
                // Show only message and no change in state
                return "Amount not present";
            }

            this.DummyCashPresent -= requestAmount;
            UpdateState();

            return string.Format(@"Amount of {0} has been withdrawn. Press Enter to proceed", requestAmount);
        }

        // Show only message and no change in state
        return "Invalid Amount";
    }

    private void UpdateState()
    {        
        Atm.currentState = new NoCashState(this);        
    }
}

The class for CASH_WITHDRAWN state:

class CashWithdrawnState : ATMState
{
    // This constructor will create new state taking values from old state
    public CashWithdrawnState(ATMState state)      
        :this(state.DummyCashPresent, state.Atm)
    {
        
    }

    // this constructor will be used by the other one
    public CashWithdrawnState(int amountRemaining, ATM atmBeingUsed)
    {
        this.Atm = atmBeingUsed;
        this.DummyCashPresent = amountRemaining;
    }

    public override string GetNextScreen()
    {
        UpdateState();
        return string.Format("Thanks you for using us, Amount left in ATM: {0}", this.DummyCashPresent.ToString());
    }

    private void UpdateState()
    {
        Atm.currentState = new NoCardState(this);
    }
}

Now with this design we are atually achieving the same functionality that we were achieving in the earlier example. This sure looks like more code but this approach is less error prone and using this approach the ATM class will need no modification. So if we need to add a new state then there will be minimal impact on code of existing state classes. So if I need to add a state for NO_CASH in this system, I just have to add a new concrete class that and hook it with the system.

class NoCashState : ATMState
{
    // This constructor will create new state taking values from old state
    public NoCashState(ATMState state)      
        :this(state.DummyCashPresent, state.Atm)
    {
        
    }

    // this constructor will be used by the other one
    public NoCashState(int amountRemaining, ATM atmBeingUsed)
    {
        this.Atm = atmBeingUsed;
        this.DummyCashPresent = amountRemaining;
    }

    public override string GetNextScreen()
    {            
        Console.WriteLine("ATM is EMPTY");
        Console.ReadLine();
        return string.Empty;
    }

    private void UpdateState()
    {
        // nothing here as someone will have to fill in cash and then
        // restart the atm, once restarted it will be in no card state
    }
}

And a minor modification in the UpdateState function of the CardValidatedState class.

private void UpdateState()
{
    if (this.DummyCashPresent == 0)
    {
        Atm.currentState = new NoCashState(this);
    }
    else
    {
        Atm.currentState = new CashWithdrawnState(this);
    }
}

Now let us test this system.

Before wrapping up let us look at the clas diagram of our application and compare it with the class diagram of GoF.

Point of interest

In this article we tried to get an overviwe of the state pattern and when could it be used. We also implemented as small application that contains a rudimentaty implementation of state pattern.

LINK: http://www.codeproject.com/Articles/489136/UnderstandingplusandplusImplementingplusStateplusP

A Simple Scheduler in C#

Introduction

One feature many Desktop and Web Applications require is to have a Scheduler. By Scheduler one means a framework which controls the parallel execution of Jobs. These Jobs can be executed only one or repeatedly. Therefore what one wishes is to have a framework which, in order to execute a Job (once or many times), it is necessary only to implement this very Job and hook it to the framework.

The goal of this article is to show how to develop this Scheduler and explaining in details the techniques and ideas behind this implementation. One may observe that, using the right design patterns and simple solutions, the outcome can be surprisingly straightforward.

The Scheduler described here is developed in a Microsoft .NET Library Project. A Microsoft .NET Console Project uses the DLL Library in order to implement and execute a few Jobs. The next sections of this article will show how exactly this is accomplished.

Background

Schedulers have always been a concern for architects when developing Enterprise Applications. Quite often the necessity for such a framework occurs because automation of parallel tasks aids immensely the user´s work, because it takes out of his or hers hand repetitive activities.

There are many ready-to-use solutions for that. On one hand, Java, for instance, provides a few schedulers, likeQuartz. On the other hand, Microsoft .NET developers can take advantage of Windows Services.

There are situations, however, that one may not be able to use these tools. For instance, one may have to deploy an ASP.NET Application in a Shared Server and the usage of Windows Services is simply not allowed.

Even if one can use frameworks to handle scheduling events, it may be quite interesting to see how a solution can be implemented for this matter. In this case, it is a combination of using Threads adequately and implementing the Template Method Design Pattern.

Architecture

In this section the architecture is discussed. Firstly, the class diagram is displayed and explained.

The class diagram consist of the framework (in the DLL Library) along with the execution program which dispatches the Jobs. The classes Job and JobManager encomposses the the framework; It is that simple, to implement this framework. The classes RepeatableJobRepeatableJob2 and SingleExecutionJob are Job implementations. Their names give away their main characteristics.

The Job class is to be implemented in order to be executed, either as a repeatable, or a single-execution task. TheJobManager class is responsible for gathering and executing all Jobs available (classes which extend Job).

The RepeatableJob and RepeatableJob2 are never-ending Jobs, meaning their code is always executed given fixed time-defined intervals.  The SingleExecutionJob has its code run one. The only purpose of these Jobs, is to print a message stating they have been executed. This illustrates beautifully their behavior in a console, when the program is executed.

The remaining class, Program, simply instantiates the JobManager and run it. The JobManager executes the Jobs asynchronously.

After understanding the general idea of the provided classes of the application, one can now comprehend the main thoughts which are the core of this Scheduler architecture. The JobManager, gathers all Job implementation of theJob class. These Job implementations must be within the .NET Project which uses the DLL holding the Scheduler framework. After gathering these Jobs, each of them is started in a new thread. The Job class has the methodExecuteTask() which triggers the Job task implementation. If the Job is to be executed once, after the task is completed the Job finishes its execution and the thread dies. In case the Job is repeatable, the task is executed repeatedly in intervals provided by the Job´s implementation. Note here that the Job class has some methods which are implemented and others which must be provided by its implementation. This technique falls into the Method Template Design Pattern.

The next sections, the most relevant parts of the code will be explained in more details so one can have a practical understanding of how to implement the Scheduler.

Using the code

The Job class is the obvious class to start discussing. One can have a better understanding of the framework simply by looking at it.

 Collapse | Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;

namespace SchedulerManager.Mechanism
{
    /// <summary>
    /// Classes which extend this abstract class are Jobs which will be
    /// started as soon as the application starts. These Jobs are executed
    /// asynchronously from the Web Application.
    /// </summary>
    public abstract class Job
    {
        /// <summary>
        /// Execute the Job itself, one ore repeatedly, depending on
        /// the job implementation.
        /// </summary>
        public void ExecuteJob()
        {
            if (IsRepeatable())
            {
                // execute the job in intervals determined by the methd
                // GetRepetionIntervalTime()
                while (true)
                {
                    DoJob();
                    Thread.Sleep(GetRepetitionIntervalTime());
                }
            }
            // since there is no repetetion, simply execute the job
            else
            {
                DoJob();
            }
        }

        /// <summary>
        /// If this method is overriden, on can get within the job
        /// parameters set just before the job is started. In this
        /// situation the application is running and the use may have
        /// access to resources which he/she has not during the thread
        /// execution. For instance, in a web application, the user has
        /// no access to the application context, when the thread is running.
        /// Note that this method must not be overriden. It is optional.
        /// </summary>
        /// <returns>Parameters to be used in the job.</returns>
        public virtual Object GetParameters()
        {
            return null;
        }

        /// <summary>
        /// Get the Job´s Name. This name uniquely identifies the Job.
        /// </summary>
        /// <returns>Job´s name.</returns>
        public abstract String GetName();

        /// <summary>
        /// The job to be executed.
        /// </summary>
        public abstract void DoJob();

        /// <summary>
        /// Determines whether a Job is to be repeated after a
        /// certain amount of time.
        /// </summary>
        /// <returns>True in case the Job is to be repeated, false otherwise.</returns>
        public abstract bool IsRepeatable();

        /// <summary>
        /// The amount of time, in milliseconds, which the Job has to wait until it is started
        /// over. This method is only useful if IJob.IsRepeatable() is true, otherwise
        /// its implementation is ignored.
        /// </summary>
        /// <returns>Interval time between this job executions.</returns>
        public abstract int GetRepetitionIntervalTime();
    }
}

This class is well commented so its reading is quite facilitated. The idea here is to provide everything a Job needs to be executed. The methods´ explanation will be given below:

  • DoJob() – Here is to be provided the task execution itself. This means all the work to be done has to be put inside this method.
  • IsRepeatable() – Determine whether the task is to be repeated or not.
  • GetRepetitionIntervalTime() – Return the interval, in milliseconds, which the Job has to wait until it is to be executed again, in case the Job is repeatable, obviously.
  • GetName() – Uniquely identifies the Job. It is very important that this name indeed is unique among the implemented Jobs in the assembly holding them, otherwise unexpected behavior is to occur.
  • GetParameters() – This method is to be implemented when one wishes to pass parameters to the task execution. In order to access the entered parameters, only simply has to call this method within the task implementation – DoJob() method.
  • ExecuteJob() – This method executes the task itself. It calls the DoJob() method. Note that in case the method is to be run repeatedly, the DoJob() is executed in a loop, otherwise it is called only one. Here is where the Method Template Design Pattern is applied. The ExecuteJob() method is executed based on its class´s method´s implementation.

The next class to be understood is the JobManager, which is displayed below:

 Collapse | Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Threading;
using log4net;
using SchedulerManager.Log4Net;

namespace SchedulerManager.Mechanism
{
    /// <summary>
    /// Job mechanism manager.
    /// </summary>
    public class JobManager
    {
        private ILog log = LogManager.GetLogger(Log4NetConstants.SCHEDULER_LOGGER);

        /// <summary>
        /// Execute all Jobs.
        /// </summary>
        public void ExecuteAllJobs()
        {
            log.Debug("Begin Method");

            try
            {
                // get all job implementations of this assembly.
                IEnumerable<Type> jobs = GetAllTypesImplementingInterface(typeof(Job));
                // execute each job
                if (jobs != null && jobs.Count() > 0)
                {
                    Job instanceJob = null;
                    Thread thread = null;
                    foreach (Type job in jobs)
                    {
                        // only instantiate the job its implementation is "real"
                        if (IsRealClass(job))
                        {
                            try
                            {
                                // instantiate job by reflection
                                instanceJob = (Job)Activator.CreateInstance(job);
                                log.Debug(String.Format(
                                  "The Job \"{0}\" has been instantiated successfully.", 
                                  instanceJob.GetName()));
                                // create thread for this job execution method
                                thread = new Thread(new ThreadStart(instanceJob.ExecuteJob));
                                // start thread executing the job
                                thread.Start();
                                log.Debug(String.Format(
                                  "The Job \"{0}\" has its thread started successfully.", 
                                  instanceJob.GetName()));
                            }
                            catch (Exception ex)
                            {
                                log.Error(String.Format("The Job \"{0}\" could not " + 
                                  "be instantiated or executed.", job.Name), ex);
                            }
                        }
                        else
                        {
                            log.Error(String.Format(
                              "The Job \"{0}\" cannot be instantiated.", job.FullName));
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                log.Error("An error has occured while instantiating " + 
                  "or executing Jobs for the Scheduler Framework.", ex);
            }

            log.Debug("End Method");
        }

        /// <summary>
        /// Returns all types in the current AppDomain implementing the interface or inheriting the type. 
        /// </summary>
        private IEnumerable<Type> GetAllTypesImplementingInterface(Type desiredType)
        {
            return AppDomain
                .CurrentDomain
                .GetAssemblies()
                .SelectMany(assembly => assembly.GetTypes())
                .Where(type => desiredType.IsAssignableFrom(type));

        }

        /// <summary>
        /// Determine whether the object is real - non-abstract, non-generic-needed, non-interface class.
        /// </summary>
        /// <param name="testType">Type to be verified.</param>
        /// <returns>True in case the class is real, false otherwise.</returns>
        public static bool IsRealClass(Type testType)
        {
            return testType.IsAbstract == false
                && testType.IsGenericTypeDefinition == false
                && testType.IsInterface == false;
        }
    }
}

Again, this class is well commented in order to ease the understanding. Have a look at the ExecuteAllJobs()method. This method, gathers all Job implementations from the assembly its being executed and run them in separate threads. Observe that this solution is quite simple. This solution does not have the dangers of deadlocks or complicated thread interactions. Furthermore, since each thread runs independently, it is very easy to debug and find errors in this framework.

One last think to be observed are the Jobs implementations. Below are displayed the SimgleExecutionJob and the  RepeatableJob ones.

 Collapse | Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SchedulerManager.Mechanism;

namespace SchedulerConsoleApp.Jobs
{
    /// <summary>
    /// A simple job which is executed only once.
    /// </summary>
    class SimgleExecutionJob : Job
    {
        /// <summary>
        /// Get the Job Name, which reflects the class name.
        /// </summary>
        /// <returns>The class Name.</returns>
        public override string GetName()
        {
            return this.GetType().Name;
        }

        /// <summary>
        /// Execute the Job itself. Just print a message.
        /// </summary>
        public override void DoJob()
        {
            System.Console.WriteLine(String.Format("The Job \"{0}\" was executed.", 
                                       this.GetName()));
        }

        /// <summary>
        /// Determines this job is not repeatable.
        /// </summary>
        /// <returns>Returns false because this job is not repeatable.</returns>
        public override bool IsRepeatable()
        {
            return false;
        }

        /// <summary>
        /// In case this method is executed NotImplementedException is thrown
        /// because this method is not to to be used. This method is never used
        /// because it serves the purpose of stating the interval of which the job
        /// will be executed repeatedly. Since this job is a single-execution one,
        /// this method is rendered useless.
        /// </summary>
        /// <returns>Returns nothing because this method is not to be used.</returns>
        public override int GetRepetitionIntervalTime()
        {
            throw new NotImplementedException();
        }
    }
}
 Collapse | Copy Code
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SchedulerManager.Mechanism;

namespace SchedulerConsoleApp.Jobs
{
    /// <summary>
    /// A simple repeatable Job.
    /// </summary>
    class RepeatableJob : Job
    {
        /// <summary>
        /// Counter used to count the number of times this job has been
        /// executed.
        /// </summary>
        private int counter = 0;

        /// <summary>
        /// Get the Job Name, which reflects the class name.
        /// </summary>
        /// <returns>The class Name.</returns>
        public override string GetName()
        {
            return this.GetType().Name;
        }

        /// <summary>
        /// Execute the Job itself. Just print a message.
        /// </summary>
        public override void DoJob()
        {
            System.Console.WriteLine(String.Format(
              "This is the execution number \"{0}\" of the Job \"{1}\".", 
              counter.ToString(), this.GetName()));
            counter++;
        }

        /// <summary>
        /// Determines this job is repeatable.
        /// </summary>
        /// <returns>Returns true because this job is repeatable.</returns>
        public override bool IsRepeatable()
        {
            return true;
        }

        /// <summary>
        /// Determines that this job is to be executed again after
        /// 1 sec.
        /// </summary>
        /// <returns>1 sec, which is the interval this job is to be
        /// executed repeatadly.</returns>
        public override int GetRepetitionIntervalTime()
        {
            return 1000;
        }
    }
}

Note how straightforward they are: the SimgleExecutionJob provides its identifier based on its class name, implements the task, which is to print a message, and tells the Job is not repeatable. The RepeatableJob, does state the task is repetitive, provides the interval of execution, gives the class name to use as its identifier, and defines its task as a simple message printing.

Compiling and Running the Code

When one opens the code and tries to compile it, errors are displayed stating that there is no log4net libraries. This occurs because it is not allowed to upload .dll files in CodeProject articles, thus the log4net.dll was removed. Therefore, to fix the Solution Setup and build it correctly, download the log4net library clicking here.  After that, create a sub-directory called libraries in the folder SchedulerManager-noexe. Inside the directory libraries copy thelog4net.dll file one has just downloaded. Finally, refresh the SchedulerManager project references and you should see that the log4net reference has no warning flag. Compile the solution and run the SchedulerConsoleApp project.

Discussion

Firstly, note the simplicity of this solution, as stated before. Simply put, one gathers all Job implementations and executes them in separate threads. This straightforwardness allows one to easily add more functionalities to this framework.

In the subject of new features, one may consider having the Job´s requirements in a database. For instance, whether or not the job is repeatable, interval of execution, could be all stored in a database, each row identified by its unique name. This makes maintenance easier because in order to change their parameters execution no code change is necessary, simply database changes are needed.

Other features, such as, interface to handle the Job Management, the ability to run, pause and cancel a Job execution could also be implemented. Note however, that while these features seem nice and fancy, in most of applications there are rarely needed.

Many people argue that dealing with threads in Web Applications can be very dangerous because it may jeopardize the Application Sever. In this author´s experience, it could not be further from the truth, at least when one is working with Internet Information Services.

 

Link gốc: http://www.codeproject.com/Articles/591271/A-Simple-Scheduler-in-Csharp

The Template Method Design Pattern using C# .Net

First of all I’ll just put this pattern in context and describe its intent as in the GOF book:

Template Method:

Define the skeleton of an algorithm in an operation, deferring some steps to

Subclasses. Template Method lets subclasses redefine certain steps of an algorithm

without changing the Algorithm’s Structure. 

 

Usage:

When you are certain about the High Level steps involved in an Algorithm/Work flow you can use the Template Pattern which allows the Base Class to define the Sequence of the Steps but permits the Sub classes to alter the implementation of any/all steps.

Example in the .Net framework:

The most common example is the Asp.Net Page Life Cycle. The Page Life Cycle has a few methods which are called in a sequence but we have the liberty to modify the functionality of any of the methods by overriding them.

Sample implementation of Template Method Pattern:

Let’s see the class diagram first:

And here goes the code:

EmailBase.cs

    1 using System;

2 using System.Collections.Generic;

3 using System.Linq;

4 using System.Text;

5 using System.Threading.Tasks;

6

7 namespace TemplateMethod

8 {

9     public abstract class EmailBase

10     {

11

12         public bool SendEmail()

13         {

14             if (CheckEmailAddress() == true) // Method1 in the sequence

15             {

16                 if (ValidateMessage() == true) // Method2 in the sequence

17                 {

18                     if (SendMail() == true) // Method3 in the sequence

19                     {

20                         return true;

21                     }

22                     else

23                     {

24                         return false;

25                     }

26

27                 }

28                 else

29                 {

30                     return false;

31                 }

32

33             }

34             else

35             {

36                 return false;

37

38             }

39

40

41         }

42

43         protected abstract bool CheckEmailAddress();

44         protected abstract bool ValidateMessage();

45         protected abstract bool SendMail();

46

47

48     }

49 }

50

EmailYahoo.cs

    1 using System;

2 using System.Collections.Generic;

3 using System.Linq;

4 using System.Text;

5 using System.Threading.Tasks;

6

7 namespace TemplateMethod

8 {

9     public class EmailYahoo:EmailBase

10     {

11

12         protected override bool CheckEmailAddress()

13         {

14             Console.WriteLine(“Checking Email Address : YahooEmail”);

15             return true;

16         }

17         protected override bool ValidateMessage()

18         {

19             Console.WriteLine(“Validating Email Message : YahooEmail”);

20             return true;

21         }

22

23

24         protected override bool SendMail()

25         {

26             Console.WriteLine(“Semding Email : YahooEmail”);

27             return true;

28         }

29

30

31     }

32 }

33

 EmailGoogle.cs

    1 using System;

2 using System.Collections.Generic;

3 using System.Linq;

4 using System.Text;

5 using System.Threading.Tasks;

6

7 namespace TemplateMethod

8 {

9     public class EmailGoogle:EmailBase

10     {

11

12         protected override bool CheckEmailAddress()

13         {

14             Console.WriteLine(“Checking Email Address : GoogleEmail”);

15             return true;

16         }

17         protected override bool ValidateMessage()

18         {

19             Console.WriteLine(“Validating Email Message : GoogleEmail”);

20             return true;

21         }

22

23

24         protected override bool SendMail()

25         {

26             Console.WriteLine(“Semding Email : GoogleEmail”);

27             return true;

28         }

29

30

31     }

32 }

33

Program.cs

    1 using System;

2 using System.Collections.Generic;

3 using System.Linq;

4 using System.Text;

5 using System.Threading.Tasks;

6

7 namespace TemplateMethod

8 {

9     class Program

10     {

11         static void Main(string[] args)

12         {

13             Console.WriteLine(“Please choose an Email Account to send an Email:”);

14             Console.WriteLine(“Choose 1 for Google”);

15             Console.WriteLine(“Choose 2 for Yahoo”);

16             string choice = Console.ReadLine();

17             EmailBase email;

17

18             if (choice == “1”)

19             {

20                 email = new EmailGoogle(); // Rather than newing it up here, you may use a factory to do so.

21                 email.SendEmail();

22

23             }

24             if (choice == “2”)

25             {

26                 email = new EmailYahoo(); // Rather than newing it up here, you may use a factory to do so.

27                 email.SendEmail();

28             }

29         }

30     }

31 }

32

Final Words:

It’s very obvious that why the Template Method Pattern is a popular pattern, everything at last revolves around Algorithms and if you are clear with the steps involved it makes real sense to delegate the duty of implementing the step’s functionality to the sub classes.

Link gốc: http://weblogs.asp.net/saurabhnijhawan/archive/2012/10/15/the-template-method-design-pattern-using-c-net.aspx

Template Method in C#

definition

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm’s structure.Frequency of use:   medium

UML class diagram

participants

The classes and/or objects participating in this pattern are:

  • AbstractClass  (DataObject)
    • defines abstract primitive operations that concrete subclasses define to implement steps of an algorithm
    • implements a template method defining the skeleton of an algorithm. The template method calls primitive operations as well as operations defined in AbstractClass or those of other objects.
  • ConcreteClass  (CustomerDataObject)
    • implements the primitive operations ot carry out subclass-specific steps of the algorithm

sample code in C#

This structural code demonstrates the Template method which provides a skeleton calling sequence of methods. One or more steps can be deferred to subclasses which implement these steps without changing the overall calling sequence.

Show code

// Template Method pattern — Structural example

This real-world code demonstrates a Template method named Run() which provides a skeleton calling sequence of methods. Implementation of these steps are deferred to the CustomerDataObject subclass which implements the Connect, Select, Process, and Disconnect methods.

Hide code

// Template Method pattern — Real World example

using System;

using System.Data;

using System.Data.OleDb;

namespace DoFactory.GangOfFour.Template.RealWorld

{

/// <summary>

/// MainApp startup class for Real-World

/// Template Design Pattern.

/// </summary>

class MainApp

{

/// <summary>

/// Entry point into console application.

/// </summary>

static void Main()

{

DataAccessObject daoCategories = new Categories();

daoCategories.Run();

DataAccessObject daoProducts = new Products();

daoProducts.Run();

// Wait for user

Console.ReadKey();

}

}

/// <summary>

/// The ‘AbstractClass’ abstract class

/// </summary>

abstract class DataAccessObject

{

protected string connectionString;

protected DataSet dataSet;

public virtual void Connect()

{

// Make sure mdb is available to app

connectionString =

“provider=Microsoft.JET.OLEDB.4.0; ” +

“data source=..\\..\\..\\db1.mdb”;

}

public abstract void Select();

public abstract void Process();

public virtual void Disconnect()

{

connectionString = “”;

}

// The ‘Template Method’

public void Run()

{

Connect();

Select();

Process();

Disconnect();

}

}

/// <summary>

/// A ‘ConcreteClass’ class

/// </summary>

class Categories : DataAccessObject

{

public override void Select()

{

string sql = “select CategoryName from Categories”;

OleDbDataAdapter dataAdapter = new OleDbDataAdapter(

sql, connectionString);

dataSet = new DataSet();

dataAdapter.Fill(dataSet, “Categories”);

}

public override void Process()

{

Console.WriteLine(“Categories —- “);

DataTable dataTable = dataSet.Tables[“Categories”];

foreach (DataRow row in dataTable.Rows)

{

Console.WriteLine(row[“CategoryName”]);

}

Console.WriteLine();

}

}

/// <summary>

/// A ‘ConcreteClass’ class

/// </summary>

class Products : DataAccessObject

{

public override void Select()

{

string sql = “select ProductName from Products”;

OleDbDataAdapter dataAdapter = new OleDbDataAdapter(

sql, connectionString);

dataSet = new DataSet();

dataAdapter.Fill(dataSet, “Products”);

}

public override void Process()

{

Console.WriteLine(“Products —- “);

DataTable dataTable = dataSet.Tables[“Products”];

foreach (DataRow row in dataTable.Rows)

{

Console.WriteLine(row[“ProductName”]);

}

Console.WriteLine();

}

}

}

Output

Categories —-
Beverages
Condiments
Confections
Dairy Products
Grains/Cereals
Meat/Poultry
Produce
SeafoodProducts —-
Chai
Chang
Aniseed Syrup
Chef Anton’s Cajun Seasoning
Chef Anton’s Gumbo Mix
Grandma’s Boysenberry Spread
Uncle Bob’s Organic Dried Pears
Northwoods Cranberry Sauce
Mishi Kobe Niku

 

Link gốc: http://dofactory.com/Patterns/PatternTemplate.aspx#_self1

Một ví dụ đơn giản về Strategy Pattern

Trong phát triển phần mềm nếu bạn biết cách áp dụng các mẫu thiết kế (design pattern) bạn sẽ nhanh chóng có được ứng dụng với thiết kế đơn giản nhưng hiệu quả khi bảo trì, nâng cấp hoặc mở rộng chúng. Một trong những mẫu thiết kế đơn giản và rất dễ triển khai mà tôi trình bài trong bài viết này đó là Strategy (còn có tên gọi khác là Policy). Sau khi mô tả cơ bản về nó tôi sẽ sử dụng ngôn ngữ Java để minh họa cho mẫu thiết kế này, bạn sẽ không mất quá nhiều thời gian để nắm được Strategy và áp dụng nó vào thực tế đâu, mà biết đâu bạn đã sử dụng nó mà không biết đó là một pattern nổi tiếng?!
Strategy là một trong số rất nhiều các mẫu thiết kế dành cho phát triển ứng dụng với OOP, bạn có thể tham khảo thêm các mẫu thiết kế khác ở đây: http://www.oodesign.com. Đây là pattern cho phép các giải thuật khác nhau có thể được lựa chọn trong thời-gian-chạy (run-time). Hay nói cách khác, Strategy định nghĩa một họ các giải thuật khác nhau, mỗi giải thuật được triển khai bởi một lớp (class) cụ thể và chúng có thể hoán đổi cho nhau tùy vào ngữ cảnh. Strategy giúp các giải thuật khác nhau độc lập với client sử dụng nó. Ví dụ, một lớp thực hiện nhiệm vụ so sánh dữ liệu đầu vào có thể sử dụng mẫu thiết kế Strategy để tự động lựa chọn giải thuật cho việc này dựa trên loại dữ liệu, nguồn gốc của chúng, lựa chọn của người dùng hay các yếu tố khác. Những yếu tố này không được biết cho tới thời-gian-chạy (runtime) và khi đó tùy vào loại dữ liệu mà hệ thống lựa chọn cách thức so sánh khác nhau. Các giải pháp so sánh được đóng gói trong các đối tượng riêng biệt sẽ được sử dụng bởi những đối tượng thực hiện việc này tại các phân vùng khác nhau của hệ thống (hoặc thậm chí ở những hệ thống khác nhau) mà không gây ra sự trùng lặp về mã lệnh.Strategy thường được biểu diễn bằng UML như sau:

Sau đây tôi sẽ sử dụng Java để minh họa một ví dụ cụ thể về Strategy.

1. Sử dụng Interface có sẵn trong Java đó là java.lang.Comparable,  interface này có phương thức compareTo() cho phép các lớp triển khai nó thực hiện việc so sánh hai đối tượng với nhau.

Bạn có thể tìm hiểu thêm Interface này ở đây:http://docs.oracle.com/javase/6/docs/api/java/lang/Comparable.html

2. Triển khai 2 lớp kế thừa Comparable, lớp Student thể hiện các đối tượng sinh viên, Product thể hiện các đối tượng sản phẩm.

Hai lớp này sẽ cài đặt phương thức compareTo() để so sánh các đối tượng Sinh viên với nhau hoặc các đối tượng Sản phẩm với nhau. Khi đó ta có sơ đồ quan hệ giữa các lớp và interface như sau:

Sau đây chúng ta cùng quan sát mã nguồn của 2 lớp này:

Lớp Student:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Student implements Comparable<Student> {
   private String rollNo;
   private String fullName;
   private double marks;
   public Student(String rollNo, String fullName, double marks) {
      this.rollNo = rollNo;
      this.fullName = fullName;
      this.marks = marks;
   }
   /* Hai sinh viên so sánh với nhau theo tên (fullName) */
   @Override
   public int compareTo(Student o) {
      if (o==null || o.fullName==null) {
         return 1;
      }
      if (this.fullName==null) {
         return -1;
      }
      return this.fullName.compareTo(o.fullName);
   }
   @Override
   public String toString() {
      return rollNo + " - " + fullName;
   }
}

Các giá trị trả về tùy thuộc vào đối tượng sinh viên kia hoặc tuy thuộc vào việc so sánh hai thuộc tính fullName của 2 đối tượng sinh viên.

Lớp Product:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class Product implements Comparable<Product> {
   private String serial;
   private String productName;
   private double price;
   public Product(String serial, String productName, double price) {
      this.serial = serial;
      this.productName = productName;
      this.price = price;
   }
   /* Hai sản phẩm so sánh với nhau theo giá bán */
   @Override
   public int compareTo(Product o) {
      if (o==null || this.price>o.price) {
         return 1;
      }
      if (this.price<o.price) {
         return -1;
      }
      return 0;
   }
   @Override
   public String toString() {
      return serial + " - " + productName;
   }
}

Các giá trị trả về tùy thuộc vào đối tượng sản phẩm kia hoặc tùy thuộc vào việc so sánh hai thuộc tính price của 2 sản phẩm với nhau.

3. Chương trình minh họa

Chương trình dưới đây thể hiện việc so sánh giữa các đội tượng sinh viên với nhau và giữa các sản phẩm với nhau. Trong phương thức compare(), Collections (đóng vai trò của lớp Context trong hình vẽ UML mô tả Strategy ở trên) cài đặt phương thức sort() tự xác định loại đối tượng và sử dụng phương thức compareTo() cho phù hợp.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public class Client {
   public static void compare(ArrayList list) {
      if (list != null && list.size()>0) {
         Collections.sort(list);
         for (Object obj : list) {
            System.out.println(" + " + obj);
         }
      }
   }
   public static void main(String[] args) {
      ArrayList<Student> students = new ArrayList<Student>();
      students.add(new Student("A01234""Minh Le Hoang"12.5));
      students.add(new Student("A01235""An Nguyen Van"15.5));
      students.add(new Student("A01235""Tuan Nguyen Anh"13.5));
      students.add(new Student("A01235""Ha Le Hoang"17.5));
      System.out.println("Sap xep sinh vien: ");
      //Hệ thống sẽ dùng phương thức compareTo() của lớp Student để so sánh các đối tượng Sinh viên:
      Client.compare(students);
      ArrayList<Product> products = new ArrayList<Product>();
      products.add(new Product("P0023""Dell Vostro 3400"1200));
      products.add(new Product("P0012""IBM Thinpad T60"1100));
      products.add(new Product("P0003""Vaio Z"3000));
      products.add(new Product("P0303""HP Pavilon"1230));
      System.out.println("Sap xep san pham: ");
      //Hệ thống sẽ dùng phương thức compareTo() của lớp Product để so sánh các đối tượng sản phẩm với nhau:
      Client.compare(products);
   }
}

Qua VD đơn giản này chắc bạn đã phần nào hiểu được về Strategy Pattern và sự hiện diện của nó trong các thiết kế sẵn có của Java như bạn đã thấy trong Comparable, mong rằng bạn sẽ áp dụng được mẫu thiết kế này cho các bài toán cụ thể của mình :o)

Link gốc: http://www.csharpvn.com/KienThuc_ChiTietKienThuc.aspx?Id=318

 

Applying the Chain of Responsibility Design Pattern

Earlier this week I made use of the Chain of Responsibility design pattern to solve a fairly straight-forward problem. I’ve always been careful when trying to apply design patterns, it’s easy to get carried away and try to force a design pattern to a problem that doesn’t really require it. In this case, I felt it was justified and hopefully you’ll think the same!

The Context

I’ll give some context to the problem before we go into exactly what the Chain of Responsibility pattern is. I was working on a HTTP service (built on ASP.NET Web API) which had an API controller action that accepted requests for some data stored in a persistent repository. My requirement was to inspect the incoming request object, and depending on certain characteristics of the request, log the request object data to zero or many different output locations. This is to enable reporting on the types of requests that the service receives. The output locations were disparate data stores such as an XML file, Excel file and SQL Server Database. The key point was that to log the request I had to inspect the content of the request, and depending on some criteria, log it to none or certain data stores. Furthermore, certain requests had to be ignored and therefore not logged.

Chain of Responsibility

When I read this requirement I knew immediately there was a design pattern for this type of problem. I had taken an Object-Oriented design pattern course at university around six years ago but couldn’t quite remember the name of the pattern. After having a quick look on the GoF website, I eventually found it – Chain of Responsibility (CoR). CoR is a software design pattern that has been classified into the “behavioral” category of patterns – these are patterns that broadly deal with objects interacting with other objects. The idea is that you have multiple handler objects chained together just like a linked list data structure. An incoming request object is passed over to the first handler in the chain, the handler (depending on its “responsibility”), inspects the request and can either:

  1. Handle the request and not pass the request down the chain of handlers
  2. Handle the request but still pass the request down the chain of handlers
  3. Not handle the request and pass the request down the chain to the next handler

Note that before a handler sends the request object down the chain, it is also responsible for checking if it is actually linked to another handler. If a handler isn’t linked to another handler, it is the last handler in the chain and therefore consumes the request.

Applying CoR to the Problem

In my case, the incoming data request to the API was my CoR request that required “handling” from a logging perspective. I implemented a separate concrete logging handler class for each of the concrete data stores (XML, Excel and SQL Server). Each logging handler inspected the request and logged the request if it matched the criteria for the handler before passing the request to the next handler. Therefore, in my case, the CoR handler behaviour corresponded to point two above.

The Implementation

Note that I’ve stripped down the code below (especially for each concrete handler) so that it is easier to see what’s going on from a design pattern perspective.

The first step was to write an abstract base handler that defined the behaviour that each of my handlers will support. The HandlerBase class below is generic enough to be reused in any case where you require a CoR implemented. The single type parameter “TRequest” is the type of the object that will go through your chain (can be any .NET type).

public abstract class HandlerBase<TRequest>
{
    public HandlerBase<TRequest> Successor
    { 
        protected get; 
        set; 
    }

    public abstract void HandleRequest(TRequest request);
}

The HandlerBase class has one property, which allows users of a handler to set a successor to this handler (the next handler in the chain) and it has an abstract method that all derived classes will need to implement – HandleRequest. You will see further below how we use the Successor property when setting up our chain, and how each concrete handler (a class that derives from HandlerBase) uses the HandleRequest method on its successor to pass the request down the chain.

Next, I implemented each of my concrete handlers – that is, a handler for logging to an XML document, Excel document and SQL server.

public class LogRequestToXmlHandler : HandlerBase<ApiDataRequest>
{
    public override void HandleRequest(ApiDataRequest request)
    {
        if (request.Foo == Something && request.Bar == SomethingElse)
            // Log request to xml document

        // Pass on the request to the next handler, if any
        if (base.Successor != null)
            base.Successor.HandleRequest(request);
    }
}

Notice how the concrete handler LogRequestToXmlHandler derives from HandlerBase and passes the type of the object that is going through the chain – ApiDataRequest. Also notice that because we’re inheriting from an abstract base class containing one abstract method – we’re forced by the compiler to override the HandleRequest method. This method accepts one parameter, the request object. It is in this method that you will place any specific handling logic for the request object – I’ve added some pseudo-code to demonstrate this. The last couple of lines inspect the Successor property (inherited from the base class), if it isn’t null – then we call the HandleRequest on it, thus passing our request down the chain. If Successor returns null, then the current handler is the last in the chain and we do nothing – effectively consuming the request. For completeness, the other handlers are below.

public class LogRequestToExcelHandler : HandlerBase<ApiDataRequest>
{
    public override void HandleRequest(ApiDataRequest request)
    {
        if (request.Foo == Something && request.Bar == SomethingElse)
            // Log request to excel document

        if (base.Successor != null)
            base.Successor.HandleRequest(request);
    }
}

public class LogRequestToDbHandler : HandlerBase<ApiDataRequest>
{
    public override void HandleRequest(ApiDataRequest request)
    {
        if (request.Foo == Something && request.Bar == SomethingElse)
            // Log request to database

        if (base.Successor != null)
            base.Successor.HandleRequest(request);
    }
}

Now that we have our handlers, the final step is to setup our chain so that it’s ready to handle requests. The code below shows how the handlers are chained together.

HandlerBase<ApiDataRequest> logToXmlHandler
    = new LogRequestToXmlHandler();
HandlerBase<ApiDataRequest> logToExcelHandler
    = new LogRequestToExcelHandler();
HandlerBase<ApiDataRequest> logToDbHandler
    = new LogRequestToDbHandler();

logToXmlHandler.Successor = logToExcelHandler;
logToExcelHandler.Successor = logToDbHandler;

The first step above was to initialise each handler that will be going into the chain. We then use the Successor property to chain the three handlers together. The beauty of using this pattern is that you can chain however many handlers you want and even make the chain configurable so that it is setup at runtime depending on some settings in a config file.

Now, when a new request came through my API, it was a simple case of invoking the HandleRequest method on the first handler in the chain and passing the ApiDataRequest object through as a parameter. This sent the object down the chain, allowing each log handler to inspect it and decide whether to log it to their individual outputs.

logToXmlHandler.HandleRequest(request);

* Update *

One thing that I missed in this post and is worth mentioning is a scenario where you don’t want each concrete handler to decide whether to pass the request on down the chain. In this case, the request would go to every handler in the chain regardless. One way to accomplish this is to update the HandlerBase class as follows:

public abstract class HandlerBase<TRequest>
{
    public HandlerBase<TRequest> Successor
    { 
        protected get; 
        set; 
    }

    public void HandleRequest(TRequest request)
    {
        Handle(request);

        if (Successor != null)
            Successor.HandleRequest(request);
    }

    protected abstract void Handle(TRequest request);
}

The updated HandlerBase now implements a public HandleRequest method which first delegates the handling logic to an abstract method (Handle) which will be overridden by a concrete handler. Once a request has been handled, a test is made to check if there is a successor and if there is, then the request is passed on. What this now means is that each concrete handler will implement just one method, Handle, and not need to worry about whether to pass the request on or not – that is done automatically in the HandleRequest method. An example concrete handler is below:

public class LogRequestToXmlHandler : HandlerBase<ApiDataRequest>
{
    protected override void Handle(ApiDataRequest request)
    {
        // Check request and log it, if required
    }
}