Practicing the Chain of Responsibility Pattern
page 4 of 8
by Xianzhong Zhu
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 33858/ 84

Introducing the Template Method Pattern to Improve the Service Explorer

In fact, in the ServiceManager definition, things are not as simple as imaged with only two methods, StartService and StartAllServices. With further examination, you can conclude ServiceManager should also include other methods, such as RegisterService, UnregisterService, etc. However, simply making use of the refactoring way "Extract Method," we cannot make more improvements with the ServiceManager class even exhausting all related tricks. At this time, we need to take up the "abstract" sword to build up a new type of structure as shown in Figure 2.

Figure 2

For the reader more clearly to hold tight upon the essence of problem, I abridged the two methods RegisterService and UnregisterService in the definition of class ServiceManager. As seen from Figure 2, class ServiceManager at this time should be an abstract one and its every method should all be defined as related to the instance object.

Now, let us delve into the main methods in class ServiceManager. First, the responsibility of method Initialize is to read the configuration document information, initialize the service object and add it into the m_serviceList object. This method will be invoked by the constructor function and used when the instances of sub-classes are created. On the other hand, there are maybe differences in special initializations when the instances of sub-classes initialize service objects (and the service objects to be initialized may also be different). In this case, we can conclude that it is unnecessary for class ServiceManager to initialize the service objects any more. Therefore, the Initialize method is defined as a protective abstract method.

The task of method LookUpServiceObject is still as before. It seeks in the m_serviceList the corresponding service object and then returns it. Because of the abstract reason, the m_serviceList object has now been defined the related instantiation field. At this time, it is not fit to define method LookUpServiceObject as a static method again. If we thoroughly inquiry into that method, we will discover the realization of that method actually undertakes the task of facilitating developers to start services, with not much relevance to the need of the client side. So, according to the principle of "Information Hiding," we do not have the necessity to expose such a method that has nothing to do with the user of the class. For this, we should set it as the type of protect for the purpose of encapsulation. Accordingly, we need to modify the StartService method, setting the parameter as the name of the service object, and then calling the LookUpServiceObject method inside the method to find out the corresponding service object and work with it.

Now, the two methods of starting service are both modified as public. Method StartService only starts a service object, while the StartAllServices method starts all the matched service objects.

Next, let us take a closer look at the StartAllService method. In this method, the m_serviceList object is looped through to locate each matched service object, and then invoke its StartService method. Note that although the m_serviceList object is acquired through method lnitialize, we still need to judge the activating mode of the service object when the StartAllService method is executed to avoid exceptions when starting the service object. However, there exists a problem that we have to judge the activating mode of the service object according to the type of the sub class-- we cannot obtain that information in the parent class. As for method StartService, it is tightly relevant to the type of the sub class-- the logic of starting services differs with different kinds of activating modes of the service objects.

To resolve such a problem, we can fall back upon the Template Method pattern to define a special abstract method GetActiveMode to acquire activating modes of the service objects. The reason that we define method GetActiveMode as an abstract method is the implementation of that method is accomplished inside the sub classes, through which we can acquire the proper activating mode of the service objects.

Similarly, the StartService method in the abstract class should also be defined as an abstract one. As for the StartAllServices method, except that the acquirement of the proper activating mode of the service objects needs to be a sub class implementation, the behavior of looping through the m_serviceList object has nothing to do with sub classes. Therefore, it can be implemented in the parent class. Moreover, the other two methods GetActiveMode and StartService will be called inside method StartAllServices. The related code is shown in Listing 7.

Listing 7

public abstract class ServiceManager
{
    protected List<ServiceObject> m_serviceList = new List<ServiceObject>();
    public ServiceManager()
    {
        Initialize();
    }
    public List<ServiceObject> ServiceList
    {
        get { return m_serviceList; }
    }
 
    protected ServiceObject LookUpServiceObject(string serviceName)
    {
        foreach (ServiceObject obj in m_serviceList)
        {
            if (obj.ServiceName.Equals(serviceName))
            {
                return obj;
            }
        }
        return null;
    }
    public void StartAllServices()
    {
        foreach (ServiceObject obj in m_serviceList)
        {
            if (obj.ActiveMode.Equals(GetActiveMode()))
            {
                StartService(obj.ServiceName);
            }
        }
    }
    protected abstract void Initialize();
    protected abstract ActiveMode GetActiveMode();
    public abstract void StartService(string serviceName);
}

Notice the access level of method GetActiveMode and StartService. The StartService method is to be invoked by exterior classes, so we set it as public. However, method GetActiveMode can only be called by ServiceManager and its sub classes, so we set it as a protected method.

Although the StamAllServices method provides a concrete implementation, it uses two abstract methods inside, which stay to be implemented in sub classes. This is just like when we define a set of templates in the parent class, and then provide a concrete implementation in sub classes according to the related template. This is exactly what the Template Method pattern means.

For example, the definition of class SingletonServiceManager is as follows.

Listing 8

public class SingletonServiceManager : ServiceManager
{
    public SingletonServiceManager() : base() { }
 
    protected override void Initialize()
    {
        //initialize all the service objects that
        //use Singleton mode, and add them into
        // the m_serviceList object…
    }
 
    protected override ActiveMode GetActiveMode()
    {
        return ActiveMode.Singleton;
    }
    
    protected override void StartService(string serviceName)
    {
        ServiceObject obj= LookUpServiceObject(
                  serviceName);
        if (obj!=null)
        {
           If(obj.CurrentState.Equals(ServiceState.
                                    Stop))
           {
              obj.CurrentState = ServiceState.Start;
           }
        }
}

Now, you see, by making use of an abstract way, we only did very small adjustment to the whole structure, but this small one step set a good keynote.


View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2021 ASPAlliance.com  |  Page Processed at 2021-12-02 8:12:07 AM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search