using System; namespaceTemplateMethodPatternDemo { // The Abstract Class defines a template method that contains a skeleton of // some algorithm, composed of calls to (usually) abstract primitive // operations. // // Concrete subclasses should implement these operations, but leave the // template method itself intact. abstractclassAbstractClass { // The template method defines the skeleton of an algorithm. publicvoidTemplateMethod() { this.BaseOperation1(); this.RequiredOperations1(); this.BaseOperation2(); this.Hook1(); this.RequiredOperation2(); this.BaseOperation3(); this.Hook2(); }
// These operations already have implementations. protectedvoidBaseOperation1() { Console.WriteLine("AbstractClass says: I am doing the bulk of the work"); }
protectedvoidBaseOperation2() { Console.WriteLine("AbstractClass says: But I let subclasses override some operations"); }
protectedvoidBaseOperation3() { Console.WriteLine("AbstractClass says: But I am doing the bulk of the work anyway"); }
// These operations have to be implemented in subclasses. protectedabstractvoidRequiredOperations1();
protectedabstractvoidRequiredOperation2();
// These are "hooks." Subclasses may override them, but it's not // mandatory since the hooks already have default (but empty) // implementation. Hooks provide additional extension points in some // crucial places of the algorithm. protectedvirtualvoidHook1() { }
protectedvirtualvoidHook2() { } }
// Concrete classes have to implement all abstract operations of the base // class. They can also override some operations with a default // implementation. classConcreteClass1 : AbstractClass { protectedoverridevoidRequiredOperations1() { Console.WriteLine("ConcreteClass1 says: Implemented Operation1"); }
classClient { // The client code calls the template method to execute the algorithm. // Client code does not have to know the concrete class of an object it // works with, as long as it works with objects through the interface of // their base class. publicstaticvoidClientCode(AbstractClass abstractClass) { // ... abstractClass.TemplateMethod(); // ... } }
classProgram { staticvoidMain(string[] args) { Console.WriteLine("Same client code can work with different subclasses:");
Client.ClientCode(new ConcreteClass1());
Console.Write("\n");
Console.WriteLine("Same client code can work with different subclasses:"); Client.ClientCode(new ConcreteClass2()); // output
// Same client code can work with different subclasses: // AbstractClass says: I am doing the bulk of the work // ConcreteClass1 says: Implemented Operation1 // AbstractClass says: But I let subclasses override some operations // ConcreteClass1 says: Implemented Operation2 // AbstractClass says: But I am doing the bulk of the work anyway
// Same client code can work with different subclasses: // AbstractClass says: I am doing the bulk of the work // ConcreteClass2 says: Implemented Operation1 // AbstractClass says: But I let subclasses override some operations // ConcreteClass2 says: Overridden Hook1 // ConcreteClass2 says: Implemented Operation2 // AbstractClass says: But I am doing the bulk of the work anyway } } }