|
1 |
| -using System; |
| 1 | +// EN: Template Method Design Pattern |
| 2 | +// |
| 3 | +// Intent: Define the skeleton of an algorithm, deferring implementation of some |
| 4 | +// steps to subclasses. Template Method lets subclasses redefine specific steps |
| 5 | +// of an algorithm without changing the algorithm's structure. |
| 6 | +// |
| 7 | +// RU: Паттерн Шаблонный метод |
| 8 | +// |
| 9 | +// Назначение: Определяет общую схему алгоритма, перекладывая реализацию |
| 10 | +// некоторых шагов на подклассы. Шаблонный метод позволяет подклассам |
| 11 | +// переопределять отдельные шаги алгоритма без изменения структуры алгоритма. |
| 12 | + |
| 13 | +using System; |
2 | 14 |
|
3 | 15 | namespace RefactoringGuru.DesignPatterns.TemplateMethod.Conceptual
|
4 | 16 | {
|
| 17 | + // EN: The Abstract Class defines a template method that contains a skeleton of |
| 18 | + // some algorithm, composed of calls to (usually) abstract primitive operations. |
| 19 | + // |
| 20 | + // Concrete subclasses should implement these operations, but leave the template |
| 21 | + // method itself intact. |
| 22 | + // |
| 23 | + // RU: Абстрактный Класс определяет шаблонный метод, содержащий скелет |
| 24 | + // некоторого алгоритма, состоящего из вызовов (обычно) абстрактных примитивных |
| 25 | + // операций. |
| 26 | + // |
| 27 | + // Конкретные подклассы должны реализовать эти операции, но оставить сам |
| 28 | + // шаблонный метод без изменений. |
5 | 29 | abstract class AbstractClass
|
6 | 30 | {
|
7 |
| - public void templateMethod() |
| 31 | + // EN: The template method defines the skeleton of an algorithm. |
| 32 | + // |
| 33 | + // RU: Шаблонный метод определяет скелет алгоритма. |
| 34 | + public void TemplateMethod() |
8 | 35 | {
|
9 |
| - this.baseOperation1(); |
10 |
| - this.requiredOperations1(); |
11 |
| - this.baseOperation2(); |
12 |
| - this.hook1(); |
13 |
| - this.requiredOperation2(); |
14 |
| - this.baseOperation3(); |
15 |
| - this.hook2(); |
| 36 | + this.BaseOperation1(); |
| 37 | + this.RequiredOperations1(); |
| 38 | + this.BaseOperation2(); |
| 39 | + this.Hook1(); |
| 40 | + this.RequiredOperation2(); |
| 41 | + this.BaseOperation3(); |
| 42 | + this.Hook2(); |
16 | 43 | }
|
17 | 44 |
|
18 |
| - protected void baseOperation1() |
| 45 | + // EN: These operations already have implementations. |
| 46 | + // |
| 47 | + // RU: Эти операции уже имеют реализации. |
| 48 | + protected void BaseOperation1() |
19 | 49 | {
|
20 |
| - Console.Write("AbstractClass says: I am doing the bulk of the work\n"); |
| 50 | + Console.WriteLine("AbstractClass says: I am doing the bulk of the work"); |
21 | 51 | }
|
22 | 52 |
|
23 |
| - protected void baseOperation2() |
| 53 | + protected void BaseOperation2() |
24 | 54 | {
|
25 |
| - Console.Write("AbstractClass says: But I let subclasses override some operations\n"); |
| 55 | + Console.WriteLine("AbstractClass says: But I let subclasses override some operations"); |
26 | 56 | }
|
27 | 57 |
|
28 |
| - protected void baseOperation3() |
| 58 | + protected void BaseOperation3() |
29 | 59 | {
|
30 |
| - Console.Write("AbstractClass says: But I am doing the bulk of the work anyway\n"); |
| 60 | + Console.WriteLine("AbstractClass says: But I am doing the bulk of the work anyway"); |
31 | 61 | }
|
32 |
| - |
33 |
| - protected abstract void requiredOperations1(); |
34 |
| - |
35 |
| - protected abstract void requiredOperation2(); |
36 |
| - |
37 |
| - protected virtual void hook1() { } |
38 |
| - |
39 |
| - protected virtual void hook2() { } |
| 62 | + |
| 63 | + // EN: These operations have to be implemented in subclasses. |
| 64 | + // |
| 65 | + // RU: А эти операции должны быть реализованы в подклассах. |
| 66 | + protected abstract void RequiredOperations1(); |
| 67 | + |
| 68 | + protected abstract void RequiredOperation2(); |
| 69 | + |
| 70 | + // EN: These are "hooks." Subclasses may override them, but it's not |
| 71 | + // mandatory since the hooks already have default (but empty) |
| 72 | + // implementation. Hooks provide additional extension points in some crucial |
| 73 | + // places of the algorithm. |
| 74 | + // |
| 75 | + // RU: Это «хуки». Подклассы могут переопределять их, но это не обязательно, |
| 76 | + // поскольку у хуков уже есть стандартная (но пустая) реализация. Хуки |
| 77 | + // предоставляют дополнительные точки расширения в некоторых критических |
| 78 | + // местах алгоритма. |
| 79 | + protected virtual void Hook1() { } |
| 80 | + |
| 81 | + protected virtual void Hook2() { } |
40 | 82 | }
|
41 | 83 |
|
| 84 | + // EN: Concrete classes have to implement all abstract operations of the base |
| 85 | + // class. They can also override some operations with a default implementation. |
| 86 | + // |
| 87 | + // RU: Конкретные классы должны реализовать все абстрактные операции базового |
| 88 | + // класса. Они также могут переопределить некоторые операции с реализацией по |
| 89 | + // умолчанию. |
42 | 90 | class ConcreteClass1 : AbstractClass
|
43 | 91 | {
|
44 |
| - protected override void requiredOperations1() |
| 92 | + protected override void RequiredOperations1() |
45 | 93 | {
|
46 |
| - Console.Write("ConcreteClass1 says: Implemented Operation1\n"); |
| 94 | + Console.WriteLine("ConcreteClass1 says: Implemented Operation1"); |
47 | 95 | }
|
48 | 96 |
|
49 |
| - protected override void requiredOperation2() |
| 97 | + protected override void RequiredOperation2() |
50 | 98 | {
|
51 |
| - Console.Write("ConcreteClass1 says: Implemented Operation2\n"); |
| 99 | + Console.WriteLine("ConcreteClass1 says: Implemented Operation2"); |
52 | 100 | }
|
53 | 101 | }
|
54 | 102 |
|
| 103 | + // EN: Usually, concrete classes override only a fraction of base class' |
| 104 | + // operations. |
| 105 | + // |
| 106 | + // RU: Обычно конкретные классы переопределяют только часть операций базового |
| 107 | + // класса. |
55 | 108 | class ConcreteClass2 : AbstractClass
|
56 | 109 | {
|
57 |
| - protected override void requiredOperations1() |
| 110 | + protected override void RequiredOperations1() |
58 | 111 | {
|
59 |
| - Console.Write("ConcreteClass2 says: Implemented Operation1\n"); |
| 112 | + Console.WriteLine("ConcreteClass2 says: Implemented Operation1"); |
60 | 113 | }
|
61 | 114 |
|
62 |
| - protected override void requiredOperation2() |
| 115 | + protected override void RequiredOperation2() |
63 | 116 | {
|
64 |
| - Console.Write("ConcreteClass2 says: Implemented Operation2\n"); |
| 117 | + Console.WriteLine("ConcreteClass2 says: Implemented Operation2"); |
65 | 118 | }
|
66 | 119 |
|
67 |
| - protected override void hook1() |
| 120 | + protected override void Hook1() |
68 | 121 | {
|
69 |
| - Console.Write("ConcreteClass2 says: Overridden Hook1\n"); |
| 122 | + Console.WriteLine("ConcreteClass2 says: Overridden Hook1"); |
70 | 123 | }
|
71 | 124 | }
|
72 | 125 |
|
73 | 126 | class Client
|
74 | 127 | {
|
75 |
| - public static void ClientCode(AbstractClass ac) |
| 128 | + // EN: The client code calls the template method to execute the algorithm. |
| 129 | + // Client code does not have to know the concrete class of an object it works |
| 130 | + // with, as long as it works with objects through the interface of their base |
| 131 | + // class. |
| 132 | + // |
| 133 | + // RU: Клиентский код вызывает шаблонный метод для выполнения алгоритма. |
| 134 | + // Клиентский код не должен знать конкретный класс объекта, с которым работает, |
| 135 | + // при условии, что он работает с объектами через интерфейс их базового класса. |
| 136 | + public static void ClientCode(AbstractClass abstractClass) |
76 | 137 | {
|
77 |
| - ac.templateMethod(); |
| 138 | + // ... |
| 139 | + abstractClass.TemplateMethod(); |
| 140 | + // ... |
78 | 141 | }
|
79 | 142 | }
|
80 | 143 |
|
81 | 144 | class Program
|
82 | 145 | {
|
83 | 146 | static void Main(string[] args)
|
84 | 147 | {
|
85 |
| - Console.Write("Same client code can work with different subclasses:\n"); |
| 148 | + Console.WriteLine("Same client code can work with different subclasses:"); |
86 | 149 |
|
87 | 150 | Client.ClientCode(new ConcreteClass1());
|
88 | 151 |
|
89 | 152 | Console.Write("\n");
|
90 |
| - Console.Write("Same client code can work with different subclasses:\n"); |
| 153 | + |
| 154 | + Console.WriteLine("Same client code can work with different subclasses:"); |
91 | 155 | Client.ClientCode(new ConcreteClass2());
|
92 | 156 | }
|
93 | 157 | }
|
|
0 commit comments