Difference between revisions of "Template Method"

From CDOT Wiki
Jump to: navigation, search
(Real-life Application)
(Apache Tomcat)
 
(33 intermediate revisions by the same user not shown)
Line 74: Line 74:
 
Source from Zend Technologies, http://www.zend.com/zend/php5/php5-OOP.php?article=php5-OOP&kind=ph&id=3204&open=1&anc=0&view=1
 
Source from Zend Technologies, http://www.zend.com/zend/php5/php5-OOP.php?article=php5-OOP&kind=ph&id=3204&open=1&anc=0&view=1
  
== Real-life Application ==
+
== Real-life Applications ==
  
 +
=== Apache Excalibur ===
 +
 +
The following are portions of the code found in [http://www.google.com/codesearch?hl=en&q=show:b65X65FJv3k:tIVs6rnDDGE:CuwdO4_VJq8&sa=N&ct=rd&cs_p=https://svn.apache.org/repos/asf/excalibur/trunk&cs_f=framework/api/src/test/org/apache/avalon/framework/test/CascadingErrorTestCase.java[CascadingErrorTestCase.java]] and [http://www.google.com/codesearch?hl=en&q=show:5CjVErg7uPw:tIVs6rnDDGE:W66LfbDC3n0&sa=N&ct=rd&cs_p=https://svn.apache.org/repos/asf/excalibur/trunk&cs_f=framework/api/src/test/org/apache/avalon/framework/test/CascadingExceptionTestCase.java[CascadingEexceptionTestCase.java]]  files.<br/><br/>
 +
When comparing these two files, we can see that the two files share a common package '''org.apache.avalon.framework.test'''.
 
<pre>
 
<pre>
/*
 
* Licensed to the Apache Software Foundation (ASF) under one or more
 
* contributor license agreements.  See the NOTICE file distributed with
 
* this work for additional information regarding copyright ownership.
 
* The ASF licenses this file to You under the Apache License, Version 2.0
 
* (the "License"); you may not use this file except in compliance with
 
* the License.  You may obtain a copy of the License at
 
*
 
*    http://www.apache.org/licenses/LICENSE-2.0
 
*
 
* Unless required by applicable law or agreed to in writing, software
 
* distributed under the License is distributed on an "AS IS" BASIS,
 
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
* See the License for the specific language governing permissions and
 
* limitations under the License.
 
*/
 
package org.apache.avalon.framework.component.test;
 
  
import junit.framework.TestCase;
+
package org.apache.avalon.framework.test;
import org.apache.avalon.framework.component.Component;
 
import org.apache.avalon.framework.component.ComponentException;
 
import org.apache.avalon.framework.component.DefaultComponentManager;
 
  
/**
+
import org.apache.avalon.framework.CascadingError;
* Test the basic public methods of DefaultComponentManager.
+
import org.apache.avalon.framework.CascadingThrowable;
*
 
* @author <a href="mailto:dev@avalon.apache.org">Avalon Development Team</a>
 
*/
 
public final class DefaultComponentManagerTestCase
 
    extends TestCase
 
{
 
  
    class DefaultRoleA
+
import junit.framework.TestCase;
        implements Component,RoleA
 
    {
 
        public DefaultRoleA()
 
        {
 
        }
 
    }
 
  
    class DefaultRoleB
+
</pre>
        implements Component,RoleB
 
    {
 
        public DefaultRoleB()
 
        {
 
        }
 
    }
 
  
 +
From the following, we can see that the class '''CascadingErrorTestCase''' is extending from an abstract class called '''TestCase'''. This is the same case in the '''CascadingExceptionTestCase.java''' file. Hence, this shows that these two classes are subclasses of the class '''TestCase'''.
  
    private DefaultComponentManager m_componentManager;
+
<pre>
 +
public class CascadingErrorTestCase extends TestCase
 +
{
 +
}
 +
</pre>
  
    protected boolean m_exceptionThrown;
+
When looking at the testConstructor() in both files, we can see that it implements different methods, therefore its altering the algorithm operation of the file. Therefore we can conclude that the general steps in the constructor is not altered, but the implementation is different.
 
+
<pre>
 
+
    // From CascadingErrorTestCase.java
     public DefaultComponentManagerTestCase()
+
     public void testConstructor()
 
     {
 
     {
         this("DefaultComponentManager Test Case");
+
         assertNotNull( new CascadingError( null, null ) );
    }
+
        assertNotNull( new CascadingError( "msg", null ) );
 +
        assertNotNull( new CascadingError( "msg", new RuntimeException() ) );
 +
        assertNotNull( new CascadingError( null, new RuntimeException() ) );
  
    public DefaultComponentManagerTestCase( final String name )
+
        //assertNotNull( new CascadingError( "msg" ) );
    {
+
        //ambiguous assertNotNull( new CascadingError( null ) );
         super( name );
+
         //assertNotNull( new CascadingError() );
 
     }
 
     }
 
+
</pre>
     protected void setUp()
+
<pre>
        throws Exception
+
    // From CascadingExceptionTestCase.java
 +
     public void testConstructor()
 
     {
 
     {
         m_componentManager = new DefaultComponentManager();
+
         assertNotNull( new CascadingException( null, null ) );
         m_exceptionThrown = false;
+
         assertNotNull( new CascadingException( "msg", null ) );
    }
+
        assertNotNull(
 +
                new CascadingException( "msg", new RuntimeException() ) );
 +
        assertNotNull( new CascadingException( null, new RuntimeException() ) );
  
    protected  void tearDown()
+
        assertNotNull( new CascadingException( "msg" ) );
         throws Exception
+
         // ambiguous assertNotNull( new CascadingException( null ) );
    {
+
         //assertNotNull( new CascadingException() );
         m_componentManager = null;
 
 
     }
 
     }
 +
</pre>
  
    /**
+
Source from [http://www.google.com/codesearch?hl=en&q=show:tIVs6rnDDGE:QLDR0Cw82Lo&sa=N&ct=rdl&cs_p=https://svn.apache.org/repos/asf/excalibur/trunk&cs_f=framework/api/src/test/org/apache/avalon/framework/test/ | Apache Excalibur Test Framework via Google Code Search]
    * lookup contract:
 
    * return first component found for role
 
    * search in hirarchy from current componentManager up.
 
    * if no compnent exist for role a in hierarchy
 
    * throw ComponentException
 
    */
 
  
 +
=== Apache Tomcat ===
  
     public void testlookup1()
+
The following are portions of the code found in [https://svn.apache.org/repos/asf/tomcat/connectors/trunk/jk/java/org/apache/jk/common/Shm.java[Shm.java]] and
         throws Exception
+
[https://svn.apache.org/repos/asf/tomcat/connectors/trunk/jk/java/org/apache/jk/common/Shm14.java[Shm14.java]]<br/><br/>
 +
Looking at the '''Shm14.java''', we can conclude that '''Shm.java''' is the base class while ''''Shm14.java'''' is the subclass. In addition, ''''Shm.java''' also extends to '''JniHandler''', making it a subclass of that class.
 +
<pre>
 +
// From Shm14.java
 +
public class Shm14 extends Shm {
 +
}
 +
</pre>
 +
<pre>
 +
// From Shm.java
 +
public class Shm extends JniHandler {
 +
}
 +
</pre>
 +
From the file '''Shm.java''', the following method is given.
 +
<pre>
 +
     public int invoke(Msg msg, MsgContext ep )
 +
         throws IOException
 
     {
 
     {
         DefaultRoleB roleBinBase = new DefaultRoleB();
+
         if( apr==null ) return 0;
        DefaultRoleB roleBinParent = new DefaultRoleB();
+
         log.debug("ChannelShm.invoke: "  + ep );
        DefaultRoleA roleAinParent = new DefaultRoleA();
+
         super.nativeDispatch( msg, ep, JK_HANDLE_SHM_DISPATCH, 0 );
 
+
         return 0;
         m_componentManager.put(RoleA.ROLE,roleAinParent);
+
    }   
         m_componentManager.put(RoleB.ROLE,roleBinParent);
+
</pre>
        DefaultComponentManager baseComponentManager = new DefaultComponentManager(m_componentManager);
+
In the ''''Shm14.java'''' file, the method from the base class is overridden with the following new one - its implementation changed, but the same structure.
         baseComponentManager.put(RoleB.ROLE,roleBinBase);
+
<pre>
        Object lookupAinBase = baseComponentManager.lookup(RoleA.ROLE);
+
     public int invoke(Msg msg, MsgContext ep )
        Object lookupBinBase = baseComponentManager.lookup(RoleB.ROLE);
+
         throws IOException
        Object lookupBinParent = m_componentManager.lookup(RoleB.ROLE);
 
        assertTrue( lookupAinBase instanceof RoleA);
 
        assertEquals( lookupBinBase, roleBinBase );
 
        assertEquals( lookupBinParent, roleBinParent );
 
        assertEquals( lookupAinBase,roleAinParent);
 
    }
 
 
 
     public void testlookup2()
 
         throws Exception
 
 
     {
 
     {
         m_componentManager.put(RoleA.ROLE,new DefaultRoleA());
+
         if (log.isDebugEnabled())
        Object o = null;
+
             log.debug("ChannelShm14.invoke: " + ep );
        try
 
        {
 
             o = m_componentManager.lookup(RoleB.ROLE);
 
        }
 
        catch        (ComponentException ce)
 
        {
 
            m_exceptionThrown = true;
 
        }
 
        if (o == null)
 
            assertTrue("ComponentException was not thrown when component was not found by lookup." ,m_exceptionThrown );
 
        else
 
            assertTrue("component was found by lookup ,when there was no component.",false);
 
 
 
    }
 
  
    public void testhasComponent()
+
         //  
        throws Exception
+
          
    {
+
         return 0;
        m_componentManager.put(RoleA.ROLE,new DefaultRoleA());
+
     }  
        assertTrue(m_componentManager.hasComponent(RoleA.ROLE));
 
        assertTrue(!m_componentManager.hasComponent(RoleB.ROLE));
 
    }
 
 
 
    public void testmakeReadOnly()
 
        throws Exception
 
    {
 
         //before read only
 
         m_componentManager.put(RoleA.ROLE,new DefaultRoleA());
 
         Object a = m_componentManager.lookup(RoleA.ROLE);
 
        assertTrue( a instanceof RoleA);
 
        m_componentManager.makeReadOnly();
 
        //after read only
 
        try
 
        {
 
            m_componentManager.put(RoleB.ROLE,new DefaultRoleB());
 
        }
 
        catch        (IllegalStateException se)
 
        {
 
            m_exceptionThrown = true;
 
        }
 
        assertTrue("IllegalStateException was not thrown in  put after makeReadOnly." , m_exceptionThrown );
 
     }
 
}
 
 
</pre>
 
</pre>
 +
Source from [https://svn.apache.org/repos/asf/tomcat/connectors/trunk/jk/java/org/apache/jk/common/ | Apache Tomcat Sample Code via Google Code Search]
  
 
== References ==
 
== References ==
 +
Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN 0-201-63361-2.<br/>
 +
[http://en.wikipedia.org/wiki/Template_method_pattern| Template Method on Wikipedia]<br/><br/><br/>
 
[[BTP600|BTP600 Wiki Page]]<br/>
 
[[BTP600|BTP600 Wiki Page]]<br/>
[http://en.wikipedia.org/wiki/Template_method_pattern| Template Method on Wikipedia]<br/>
 

Latest revision as of 18:56, 19 March 2007

Template Method

Template Method, a class behavioral pattern, provides the general steps of a method while deferring the implementation to its subclasses. Used to encapsulate algorithms, it can help reduce code duplication and maximizes the reuse of subclasses. Generally, an abstract base class is created, defining a template method of an algorithm. Later on, the subclasses can alter and implement the behavior.

UML Diagram

TemplateMethod.JPG

Source from GoF's Design Patterns - Elements of Reusable Object -Oriented Software (pg. 325)

Code Examples

Java

//Coercion Polymorphism
abstract class Add {
   public abstract double add(double d1, double d2);//template
}
class AddAnyTypeNumber extends Add{
    public double add(double d1, double d2) {
        return d1 + d2;
    }
}
class Test {
   public static void main(String[] args) {
       double d1 = 10.5, d2 = 9.5;
       float f1 = 11.5f, f2 = 12.5f;
       long l1 = 1, l2 = 2;
       int i1 = 3, i2 = 4;
       short s1 = 7, s2 = 8;
       byte b1 = 5, b2 = 6;
       
       AddAnyTypeNumber addNumber = new AddAnyTypeNumber();
       
       System.out.println(addNumber.add(d1,d2));
       System.out.println((float)addNumber.add(f1,f2));
       System.out.println((long)addNumber.add(l1,l2));
       System.out.println((int)addNumber.add(i1,i2));
       System.out.println((short)addNumber.add(s1,s2));
       System.out.println((byte)addNumber.add(b1,b2));
   }
}

Source from Javacamp, http://www.javacamp.org/designPattern/template.html/

PHP 5.0

abstract class AbstractClass {
    public final function templateMethod() {
        print "AbstractClass::templateMethod() called.\n";
        
        $this->mandatoryOperation();
        $this->optionalOperation();
    }

    protected abstract function mandatoryOperation();

    protected function optionalOperation() {
    }
}
class ConcreteClass extends AbstractClass {
    protected function mandatoryOperation() {
        print "ConcreteClass::mandatoryOperation() called.\n";
    }

    protected function optionalOperation() {
        print "ConcreteClass::optionalOperation() called.\n";
    }
}

Source from Zend Technologies, http://www.zend.com/zend/php5/php5-OOP.php?article=php5-OOP&kind=ph&id=3204&open=1&anc=0&view=1

Real-life Applications

Apache Excalibur

The following are portions of the code found in [CascadingErrorTestCase.java] and [CascadingEexceptionTestCase.java] files.

When comparing these two files, we can see that the two files share a common package org.apache.avalon.framework.test.


package org.apache.avalon.framework.test;

import org.apache.avalon.framework.CascadingError;
import org.apache.avalon.framework.CascadingThrowable;

import junit.framework.TestCase;

From the following, we can see that the class CascadingErrorTestCase is extending from an abstract class called TestCase. This is the same case in the CascadingExceptionTestCase.java file. Hence, this shows that these two classes are subclasses of the class TestCase.

public class CascadingErrorTestCase extends TestCase
{
}

When looking at the testConstructor() in both files, we can see that it implements different methods, therefore its altering the algorithm operation of the file. Therefore we can conclude that the general steps in the constructor is not altered, but the implementation is different.

    // From CascadingErrorTestCase.java
    public void testConstructor()
    {
        assertNotNull( new CascadingError( null, null ) );
        assertNotNull( new CascadingError( "msg", null ) );
        assertNotNull( new CascadingError( "msg", new RuntimeException() ) );
        assertNotNull( new CascadingError( null, new RuntimeException() ) );

        //assertNotNull( new CascadingError( "msg" ) );
        //ambiguous assertNotNull( new CascadingError( null ) );
        //assertNotNull( new CascadingError() );
    }
    // From CascadingExceptionTestCase.java
    public void testConstructor()
    {
        assertNotNull( new CascadingException( null, null ) );
        assertNotNull( new CascadingException( "msg", null ) );
        assertNotNull(
                new CascadingException( "msg", new RuntimeException() ) );
        assertNotNull( new CascadingException( null, new RuntimeException() ) );

        assertNotNull( new CascadingException( "msg" ) );
        // ambiguous assertNotNull( new CascadingException( null ) );
        //assertNotNull( new CascadingException() );
    }

Source from | Apache Excalibur Test Framework via Google Code Search

Apache Tomcat

The following are portions of the code found in [Shm.java] and [Shm14.java]

Looking at the Shm14.java, we can conclude that Shm.java is the base class while 'Shm14.java' is the subclass. In addition, 'Shm.java also extends to JniHandler, making it a subclass of that class.

// From Shm14.java
public class Shm14 extends Shm {
}
// From Shm.java
public class Shm extends JniHandler {
}

From the file Shm.java, the following method is given.

    public  int invoke(Msg msg, MsgContext ep )
        throws IOException
    {
        if( apr==null ) return 0;
        log.debug("ChannelShm.invoke: "  + ep );
        super.nativeDispatch( msg, ep, JK_HANDLE_SHM_DISPATCH, 0 );
        return 0;
    }    

In the 'Shm14.java' file, the method from the base class is overridden with the following new one - its implementation changed, but the same structure.

    public  int invoke(Msg msg, MsgContext ep )
        throws IOException
    {
        if (log.isDebugEnabled())
            log.debug("ChannelShm14.invoke: "  + ep );

        // 
        
        return 0;
    } 

Source from | Apache Tomcat Sample Code via Google Code Search

References

Gamma, Erich; Helm, Richard; Johnson, Ralph; Vlissides, John (1994). Design Patterns: Elements of Reusable Object-Oriented Software. Addison-Wesley. ISBN 0-201-63361-2.
Template Method on Wikipedia


BTP600 Wiki Page