Template Methodパターン
スーパークラスで処理の枠組み、サブクラスで内容を定める
ソフトウェアを作っていると、何ヶ所かで同じような処理を記述しているのに気づくことがあります。そういった時は、同じような処理の部分を1つにまとめ、共通化することになります。
手続き型のプログラミング言語では、同じような処理の部分を1つの共通関数としてまとめて、異なる部分は、引数に応じた場合分けで対応したりします。
オブジェクト指向言語では、同じような処理の部分を1つのクラスとしてまとめます。そして、それを継承したサブクラスを作り、それぞれに異なる部分だけを実装します。この時、サブクラスごとに異なる部分は抽象メソッドとして、スーパークラスで空の定義をしておくことも多いです。この時、出来上がったクラスの構成は、Template Methodパターンの形になります。
将来の機能拡張に備えて、基本となるクラスでは積極的にTemplate Methodパターンを採用して、サブクラスを作った時にオーバーライドできるようなメソッドをたくさん用意しているケースも見かけます。
しかし、場合によっては、機能の拡張を継承ではなく委譲(インスタンスを生成しメソッド呼び出し)によって行う方が適しているケースもあります。そういったケースでは、予めTemplate Methodパターンを前提とした枠組みが組まれていると、かえって弊害となることもあります。

Template Methodパターンを使うと、アルゴリズムはスーパークラスに書かれていますので、サブクラスにいちいち記述する必要がなくなります。アルゴリズムにバグが見つかっても、スーパークラスさえ直せばよい、ということになります。反面、サブクラスからは、スーパークラスで宣言されているメソッドがどういうタイミングで呼び出されているかはわかりません。よって、各メソッドの呼び出される順番がわからないとサブクラスに実装できないというような場合には、スーパークラスのソースを見て、そのタイミングを確認しないと、サブクラスの実装が難しい場合もあります。
Template Methodパターンでは、アルゴリズムをスーパークラスに記述し、その中で呼ばれているメソッドの実装(メソッドの実際の処理内容)はサブクラスに記述します。どのレベルで処理を分けるか、その処理をスーパークラスに置き、どの処理をサブクラスに置くかについては、定まったマニュアルがあるわけではありません。それは、プログラムの設計を行う人に任されています。
スーパークラスの記述を多くすれば、サブクラスの記述は楽になりますが、自由度は減るといって良いでしょう。逆にスーパークラスの記述が少なくなれば、サブクラスの記述は大変になり、また個々のサブクラスで、処理が重複して記述されることになるかもしれません。
例題
与えられた文字を<<と>>で挟んで5回表示するクラス CharDisplay や文字列を枠で囲って5回表示するクラス StringDisplay を作りなさい。
| CharDisplay <<AAAAA>> | StringDisplay+-------+ |
|
Template Methodパターンを使用しない例 CharDisplay.java public class CharDisplay {
private char ch;
public CharDisplay(char ch) {
this.ch = ch;
}
public void display() {
System.out.print("<<");
for (int i = 0; i < 5; i++)
System.out.print(ch);
System.out.println(">>");
}
}
StringDisplay.java public class StringDisplay {
private String str;
private int width;
public StringDisplay(String str) {
this.str = str;
this.width = str.getBytes().length;
}
public void display() {
printLine();
for (int i = 0; i < 5; i++)
System.out.println("|" + str + "|");
printLine();
}
private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++)
System.out.print("-");
System.out.println("+");
}
}
Main.java public class Main {
public static void main(String[] args) {
CharDisplay d1 = new CharDisplay('A');
d1.display();
StringDisplay d2 = new StringDisplay("Hello");
d2.display();
}
}
|
Template Methodパターンを使用した例 AbstractDisplay.java public abstract class AbstractDisplay {
protected abstract void open();
protected abstract void print();
protected abstract void close();
public final void display() {
open();
for (int i = 0; i < 5; i++)
print();
close();
}
}
CharDisplay.java public class CharDisplay extends AbstractDisplay {
private char ch;
public CharDisplay(char ch) {
this.ch = ch;
}
protected void open() {
System.out.print("<<");
}
protected void print() {
System.out.print(ch);
}
protected void close() {
System.out.println(">>");
}
}
StringDisplay.java public class StringDisplay extends AbstractDisplay {
private String str;
private int width;
public StringDisplay(String str) {
this.str = str;
this.width = str.getBytes().length;
}
public void open() {
printLine();
}
public void print() {
System.out.println("|" + str + "|");
}
public void close() {
printLine();
}
private void printLine() {
System.out.print("+");
for (int i = 0; i < width; i++)
System.out.print("-");
System.out.println("+");
}
}
Main.java public class Main {
public static void main(String[] args) {
AbstractDisplay d = new CharDisplay('A');
d.display();
d = new StringDisplay("Hello");
d.display();
}
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 charDisplay.h class CharDisplay
{
private:
char ch;
public:
CharDisplay(void);
CharDisplay(char);
virtual ~CharDisplay(void);
void display(void);
}; charDisplay.cpp #include <iostream>
using namespace std;
#include "charDisplay.h"
CharDisplay::CharDisplay(void) {}
CharDisplay::CharDisplay(char ch) : ch(ch) {}
CharDisplay::~CharDisplay(void) {}
void CharDisplay::display(void)
{
cout << "<<";
for (int i = 0; i < 5; i++)
{
cout << ch;
}
cout << ">>" << endl;
}
stringDisplay.h #include <string>
class StringDisplay
{
private:
std::string str;
int width;
void printLine(void);
public:
StringDisplay(void);
StringDisplay(std::string);
virtual ~StringDisplay(void);
void display(void);
};
stringDisplay.cpp #include <iostream>
using namespace std;
#include "stringDisplay.h"
StringDisplay::StringDisplay(void) {}
StringDisplay::StringDisplay(string str) : str(str), width(str.length()) {}
StringDisplay::~StringDisplay(void) {}
void StringDisplay::display(void)
{
printLine();
for (int i = 0; i < 5; i++)
{
cout << "|" + str + "|" << endl;
}
printLine();
}
void StringDisplay::printLine(void)
{
cout << "+" + string(width, '-') + "+" << endl;
}
main.cpp #include "charDisplay.h"
#include "stringDisplay.h"
int main() {
{
CharDisplay* d1 = new CharDisplay('A');
d1->display();
delete d1;
StringDisplay* d2 = new StringDisplay("Hello");
d2->display();
delete d2;
return 0;
} |
Template Methodパターンを使用した例 abstractDisplay.h class AbstractDisplay
{
protected:
virtual void open(void) = 0;
virtual void print(void) = 0;
virtual void close(void) = 0;
public:
AbstractDisplay(void);
virtual ~AbstractDisplay(void);
void display(void);
}; abstractDisplay.cpp #include "abstractDisplay.h"
AbstractDisplay::AbstractDisplay(void) {}
AbstractDisplay::~AbstractDisplay(void) {}
void AbstractDisplay::display()
{
open();
for (int i = 0; i < 5; i++)
{
print();
}
close();
}
charDisplay.h #include "abstractDisplay.h"
class CharDisplay : public AbstractDisplay
{
private:
char ch;
protected:
void open(void);
void print(void);
void close(void);
public:
CharDisplay(void);
CharDisplay(char);
virtual ~CharDisplay(void);
};
charDisplay.cpp #include <iostream>
using namespace std;
#include "charDisplay.h"
CharDisplay::CharDisplay(void) {}
CharDisplay::CharDisplay(char ch) : ch(ch) {}
CharDisplay::~CharDisplay(void) {}
void CharDisplay::open()
{
cout << "<<";
}
void CharDisplay::print()
{
cout << ch;
}
void CharDisplay::close()
{
cout << ">>" << endl;
}
stringDisplay.h #include <string>
#include "abstractDisplay.h"
class StringDisplay : public AbstractDisplay
{
private:
std::string str;
int width;
void printLine(void);
protected:
void open(void);
void print(void);
void close(void);
public:
StringDisplay(void);
StringDisplay(std::string);
virtual ~StringDisplay(void);
};
stringDisplay.cpp #include <iostream>
using namespace std;
#include "stringDisplay.h"
StringDisplay::StringDisplay(void) {}
StringDisplay::StringDisplay(string str) : str(str), width(str.length()) {}
StringDisplay::~StringDisplay(void) {}
void StringDisplay::open()
{
printLine();
}
void StringDisplay::print()
{
cout << "|" + str + "|" << endl;
}
void StringDisplay::close()
{
printLine();
}
void StringDisplay::printLine()
{
cout << "+" + string(width, '-') + "+" << endl;
}
main.cpp #include "charDisplay.h"
#include "stringDisplay.h"
int main()
{
AbstractDisplay* d = new CharDisplay('A');
d->display();
delete d;
d = new StringDisplay("Hello");
d->display();
delete d;
return 0;
} | ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.cs class CharDisplay
{
private char ch;
public CharDisplay(char ch)
{
this.ch = ch;
}
public void Display()
{
Console.Write("<<");
for (int i = 0; i < 5; i++)
{
Console.Write(ch);
}
Console.WriteLine(">>");
}
}
StringDisplay.cs class StringDisplay
{
private string str;
private int width;
public StringDisplay(string str)
{
this.str = str;
width = str.Length;
}
public void Display()
{
PrintLine();
for (int i = 0; i < 5; i++)
{
Console.WriteLine("|" + str + "|");
}
PrintLine();
}
private void PrintLine()
{
Console.WriteLine("+" + new string('-', width) + "+");
}
}
Program.cs class Program
{
static void Main(string[] args)
{
CharDisplay d1 = new CharDisplay('A');
StringDisplay d2 = new StringDisplay("Hello");
d1.Display();
d2.Display();
}
}
|
Template Methodパターンを使用した例 AbstractDisplay.cs abstract class AbstractDisplay
{
protected abstract void Open();
protected abstract void Print();
protected abstract void Close();
public void Display()
{
Open();
for(int i = 0; i < 5; i++)
{
Print();
}
Close();
}
}
CharDisplay.cs class CharDisplay : AbstractDisplay
{
private char ch;
public CharDisplay(char ch)
{
this.ch = ch;
}
protected override void Open()
{
Console.Write("<<");
}
protected override void Print()
{
Console.Write(ch);
}
protected override void Close()
{
Console.WriteLine(">>");
}
}
StringDisplay.cs class StringDisplay : AbstractDisplay
{
private string str;
private int width;
public StringDisplay(string str)
{
this.str = str;
width = str.Length;
}
protected override void Open()
{
PrintLine();
}
protected override void Print()
{
Console.WriteLine("|" + str + "|");
}
protected override void Close()
{
PrintLine();
}
private void PrintLine()
{
Console.WriteLine("+" + new string('-', width) + "+");
}
}
Program.cs class Program
{
static void Main(string[] args)
{
AbstractDisplay d = new CharDisplay('A');
d.Display();
d = new StringDisplay("Hello");
d.Display();
}
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の Display() メソッドに記述されています。 最初に Open()、次に Print()を5回、最後に Close() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ Open() では何をする、Print() では何をする、Close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.vb Public Class CharDisplay
Private ch As Char
Public Sub New(ByVal ch As Char)
Me.ch = ch
End Sub
Public Sub Display()
Console.Write("<<")
For i As Integer = 0 To 4
Console.Write(ch)
Next
Console.WriteLine(">>")
End Sub
End Class
StringDisplay.vb Public Class StringDisplay
Private str As String
Private width As Integer
Public Sub New(ByVal str As String)
Me.str = str
width = str.Length
End Sub
Public Sub Display()
PrintLine()
For i As Integer = 0 To 4
Console.WriteLine("|" & str & "|")
Next
PrintLine()
End Sub
Private Sub PrintLine()
Console.WriteLine("+" + New String("-"c, width) + "+")
End Sub
End Class
Program.vb Module Main
Sub Main()
Dim d1 As CharDisplay = New CharDisplay("A")
Dim d2 As StringDisplay = New StringDisplay("Hello")
d1.Display()
d2.Display()
End Sub
End Module
|
Template Methodパターンを使用した例 AbstractDisplay.vb Public MustInherit Class AbstractDisplay
Protected MustOverride Sub Open()
Protected MustOverride Sub Print()
Protected MustOverride Sub Close()
Public Sub Display()
Open()
For i As Integer = 0 To 4
Print()
Next
Close()
End Sub
End Class
CharDisplay.vb Public Class CharDisplay
Inherits AbstractDisplay
Private ch As Char
Public Sub New(ByVal ch As Char)
Me.ch = ch
End Sub
Protected Overrides Sub Open()
Console.Write("<<")
End Sub
Protected Overrides Sub Print()
Console.Write(ch)
End Sub
Protected Overrides Sub Close()
Console.WriteLine(">>")
End Sub
End Class
StringDisplay.vb Public Class StringDisplay
Inherits AbstractDisplay
Private str As String
Private width As Integer
Public Sub New(ByVal str As String)
Me.str = str
width = str.Length
End Sub
Protected Overrides Sub Open()
PrintLine()
End Sub
Protected Overrides Sub Print()
Console.WriteLine("|" & str & "|")
End Sub
Protected Overrides Sub Close()
PrintLine()
End Sub
Private Sub PrintLine()
Console.WriteLine("+" + New String("-"c, width) + "+")
End Sub
End Class
Program.vb Module Main
Sub Main()
Dim d As AbstractDisplay = New CharDisplay("A")
d.Display()
d = New StringDisplay("Hello")
d.Display()
End Sub
End Module
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の Display() メソッドに記述されています。 最初に Open()、次に Print()を5回、最後に Close() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ Open() では何をする、Print() では何をする、Close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.js module.exports = class CharDisplay {
constructor(ch) {
this.ch = ch;
}
display() {
process.stdout.write("<<" + this.ch.repeat(5) + ">>\n");
}
}
StringDisplay.js module.exports = class StringDisplay {
constructor(str) {
this.str = str;
this.width = str.length;
}
display() {
this.printLine();
for (int i = 0; i < 5; i++)
process.stdout.write("|" + this.str + "|\n");
this.printLine();
}
printLine() {
process.stdout.write("+" + "-".repeat(this.width) + "+\n");
}
}
Main.js const CharDisplay = require("./CharDisplay.js");
const StringDisplay = require("./StringDisplay.js");
let d1 = new CharDisplay('A');
d1.display();
let d2 = new StringDisplay("Hello");
d2.display();
|
Template Methodパターンを使用した例 AbstractDisplay.java module.exports = class AbstractDisplay {
open() { console.log("open メソッドを定義してください。"); }
print() { console.log("print メソッドを定義してください。"); }
close() { console.log("close メソッドを定義してください。"); }
display() {
this.open();
for (let i = 0; i < 5; i++)
this.print();
this.close();
}
}
CharDisplay.js const AbstractDisplay = require("./AbstractDisplay.js");
module.exports = class CharDisplay extends AbstractDisplay {
constructor(ch) {
super();
this.ch = ch;
}
open() {
process.stdout.write("<<");
}
print() {
process.stdout.write(ch);
}
close() {
process.stdout.write(">>\n");
}
}
StringDisplay.js const AbstractDisplay = require("./AbstractDisplay.js");
module.exports = class StringDisplay extends AbstractDisplay {
constructor(str) {
super();
this.str = str;
this.width = str.length;
}
open() {
this.printLine();
}
print() {
process.stdout.write("|" + str + "|\n");
}
close() {
this.printLine();
}
printLine() {
process.stdout.write("+" + "-".repeat(this.width) + "+\n");
}
}
Main.js const CharDisplay = require("./CharDisplay.js");
const StringDisplay = require("./StringDisplay.js");
let d = new CharDisplay('A');
d.display();
d = new StringDisplay("Hello");
d.display();
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.pm package CharDisplay {
sub new {
my ($class, $ch) = @_;
my $this = { ch => $ch };
return bless $this, $class;
}
sub display {
my ($this) = @_;
print "<<" . $this->{ch} x 5 . ">>\n";
}
}
1;
StringDisplay.pm package StringDisplay {
sub new {
my ($class, $str) = @_;
my $this = { str => $str,
width => length $str
};
return bless $this, $class;
}
sub display {
my ($this) = @_;
$this->printLine();
for (1 .. 5) {
print "|" . $this->{str} . "|\n";
}
$this->printLine();
}
sub printLine {
my ($this) = @_;
print "+" . "-" x $this->{width} . "+\n";
}
}
1;
Main.pl use lib qw(./);
use CharDisplay;
use StringDisplay;
my d1 = new CharDisplay('A');
d1->display();
my d2 = new StringDisplay("Hello");
d2->display();
|
Template Methodパターンを使用した例 AbstractDisplay.pm package AbstractDisplay {
sub open { print "open メソッドを定義してください。"; }
sub print { print "print メソッドを定義してください。"; }
sub close { print "close メソッドを定義してください。"; }
sub display {
my ($this) = @_;
$this->open();
for (1 .. 5) {
$this->print();
}
$this->close();
}
}
1;
CharDisplay.pm package CharDisplay {
use base qw(AbstractDisplay);
sub new {
my ($class, $ch) = @_;
my $this = { ch => $ch };
return bless $this, $class;
}
sub open {
print "<<";
}
sub print {
my ($this) = @_;
print $this->{ch};
}
sub close {
print ">>\n";
}
}
1;
StringDisplay.pm package StringDisplay {
use base qw(AbstractDisplay);
sub new {
my ($class, $str) = @_;
my $this = { str => $str,
width => length $str
};
return bless $this, $class;
}
sub open {
my ($this) = @_;
$this->printLine();
}
sub print {
my ($this) = @_;
print "|" . $this->{str} . "|\n";
}
sub close {
my ($this) = @_;
$this->printLine();
}
sub printLine {
my ($this) = @_;
print "+" . "-" x $this->{width} . "+\n";
}
}
1;
Main.pl use lib qw(./);
use CharDisplay;
use StringDisplay;
my $d = new CharDisplay('A');
$d->display();
$d = new StringDisplay("Hello");
$d->display();
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.rb class CharDisplay
def initialize(ch)
@ch = ch
end
def display()
puts("<<" + @ch * 5 + ">>")
end
end
StringDisplay.rb class StringDisplay
def initialize(str) {
@str = str
@width = str.length
end
def display()
printLine()
for i in 1..5 do
puts |" + @str + "|"
end
printLine()
end
def printLine()
puts "+" + "-" * @width + "+"
end
end
Main.rb require './CharDisplay'
require './StringDisplay'
d1 = CharDisplay.new('A')
d1.display()
d2 = StringDisplay.new("Hello")
d2.display()
|
Template Methodパターンを使用した例 AbstractDisplay.rb class AbstractDisplay
def open()
puts "open メソッドを定義してください。"
end
def printx()
puts "printx メソッドを定義してください。"
end
def close()
puts "close メソッドを定義してください。"
end
def display() {
open();
for i in 1..5 do
printx()
end
close()
end
end
CharDisplay.rb require './AbstractDisplay'
class CharDisplay < AbstractDisplay
def initialize(ch)
@ch = ch;
end
def open()
print "<<"
end
def printx()
print ch
end
def close()
print ">>"
end
end
StringDisplay.rb require './AbstractDisplay'
class StringDisplay < AbstractDisplay
def initialize(str)
@str = str;
@width = str.length;
end
def open()
printLine()
end
def printx()
puts "|" + @str + "|"
end
def close()
printLine()
end
def printLine()
puts "+" + "-" * @width + "+"
end
end
Main.rb require './CharDisplay'
require './StringDisplay'
d = CharDisplay.new('A')
d.display()
d = StringDisplay.new("Hello")
d.display()
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprintx()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、printx() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.py class CharDisplay:
def __init__(self, ch):
self.ch = ch
def display(self):
print(f"<<{self}.ch * 5}>>")
StringDisplay.py class StringDisplay:
def __init__(self, str):
self.str = str
self.width = len(str)
def display(self):
self.__printLine()
for i in range(5):
print(f"|{self.str}|")
self.__printLine()
def __printLine(self):
print("+" + "-" * self.width + "+")
Main.py from CharDisplay import CharDisplay
from StringDisplay import StringDisplay
d1 = CharDisplay('A')
d1.display()
d2 = StringDisplay("Hello")
d2.display()
|
Template Methodパターンを使用した例 AbstractDisplay.py from abc import ABCMeta, abstractmethod
class AbstractDisplay(metaclass=ABCMeta):
@abstractmethod
def open(self):
pass
@abstractmethod
def print(self):
pass
@abstractmethod
def close(self):
pass
def display(self):
self.open()
for i in range(5):
self.print()
self.close()
CharDisplay.py from AbstractDisplay import AbstractDisplay
class CharDisplay(AbstractDisplay):
def __init__(self, ch):
super().__init__()
self.ch = ch
def open(self):
print("<<", end="")
def print(self):
print(self.ch, end="")
def close(self):
print(">>")
StringDisplay.py from AbstractDisplay import AbstractDisplay
class StringDisplay(AbstractDisplay):
def __init__(self, str):
super().__init__()
self.str = str
self.width = len(str)
def open(self):
self.__printLine()
def print(self):
print(f"|{self.str}|")
def close(self):
self.__printLine()
def __printLine(self):
print("+" + "-" * self.width + "+")
Main.js from CharDisplay import CharDisplay
from StringDisplay import StringDisplay
d = CharDisplay('A')
d.display()
d = StringDisplay("Hello")
d.display()
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.php <?php
class CharDisplay {
public function __construct($ch) {
$this->ch = ch;
}
public function display() {
print "<<";
print str_repeat($this->ch, 5);
print ">>\n";
}
}
?>
StringDisplay.php <?php
class StringDisplay {
public function __construct($str) {
$this->str = $str;
$this->width = strlen($str);
}
public function display() {
$this->printLine();
for (int $i = 0; $i < 5; $i++)
print("|" . $this->str . "|\n");
$this->printLine();
}
private function printLine() {
print "+";
print str_repeat("-", $this->width);
print("+\n");
}
}
?>
Main.php <?php
require_once('CharDisplay.php');
require_once('StringDisplay.php');
$d1 = new CharDisplay('A');
$d1->display();
$d2 = new StringDisplay("Hello");
$d2->display();
?>
|
Template Methodパターンを使用した例 AbstractDisplay.php abstract class AbstractDisplay {
protected abstract function open();
protected abstract function printx();
protected abstract function close();
public function display() {
$this->open();
for ($i = 0; $i < 5; $i++)
$this->printx();
$this->close();
}
}
?>
CharDisplay.php <?php
require_once('AbstractDisplay.php');
class CharDisplay extends AbstractDisplay {
public function __construct($ch) {
$this->ch = $ch;
}
protected function open() {
print "<<";
}
protected function printx() {
print $this->ch;
}
protected void close() {
print ">>\n";
}
}
?>
StringDisplay.java <?php
require_once('AbstractDisplay.php');
class StringDisplay extends AbstractDisplay {
public function __construct($str) {
$this->str = $str;
$this->width = strlen($str);
}
protected function open() {
$this->printLine();
}
protected function printx() {
print "|" . $this->str . "|\n";
}
protected function close() {
$this->printLine();
}
private function printLine() {
print "+";
print str_repeat("-", $this->width);
print "+\n";
}
}
?>
Main.php <?php
require_once('CharDisplay.php');
require_once('StringDisplay.php');
$d = new CharDisplay('A');
$d->display();
$d = new StringDisplay("Hello");
$d->display();
?>
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprintx()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、printx() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.ts export
class CharDisplay {
private ch:string;
public constructor(ch:string) {
this.ch = ch;
}
public display():void {
process.stdout.write("<<" + this.ch.repeat(5) + ">>\n");
}
}
StringDisplay.ts export
class StringDisplay {
private str:string;
private width:number;
public constructor(str:string) {
this.str = str;
this.width = str.length;
}
public display():void {
this.printLine();
for (let i:number = 0; i < 5; i++)
process.stdout.write("|" + this.str + "|");
this.printLine();
}
private printLine():void {
process.stdout.write("+" + "-".repeat(this.width) + "+\n");
}
}
Main.ts import {CharDisplay} from "./CharDisplay";
import {StringDisplay} from "./StringDisplay";
let d1:CharDisplay = new CharDisplay('A');
d1.display();
let d2:StringDisplay = new StringDisplay("Hello");
d2.display();
|
Template Methodパターンを使用した例 AbstractDisplay.ts export
abstract class AbstractDisplay {
protected abstract open():void;
protected abstract print():void;
protected abstract close():void;
public display():void {
this.open();
for (i:number = 0; i < 5; i++)
this.print();
this.close();
}
}
CharDisplay.ts import {AbstractDisplay} from "./AbstractDisplay";
export
class CharDisplay extends AbstractDisplay {
private ch:string;
public constructor(ch:string) {
super();
this.ch = ch;
}
protected open():void {
process.stdout.write("<<");
}
protected print():void {
process.stdout.write(this.ch);
}
protected close():void {
process.stdout.write(">>\n");
}
}
StringDisplay.ts import {AbstractDisplay} from "./AbstractDisplay";
export
class StringDisplay extends AbstractDisplay {
private str:string;
private width:number;
public constructor(str:string) {
super();
this.str = str;
this.width = str.length;
}
protected open():void {
this.printLine();
}
protected print():void {
process.stdout.write("|" + this.str + "|");
}
protected close():void {
this.printLine();
}
private printLine():void {
process.stdout.write("+" + "-".repeat(this.width) + "+\n");
}
}
Main.ts import {AbstractDisplay} from "./AbstractDisplay";
import {CharDisplay} from "./CharDisplay";
import {StringDisplay} from "./StringDisplay";
let d:AbstractDisplay = new CharDisplay('A');
d.display();
d = new StringDisplay("Hello");
d.display();
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.swift public class CharDisplay {
private var ch:Character
public init(_ ch:Character) {
self.ch = ch
}
public func display() {
print("<<" + String.init(repeating:ch, count:5) + ">>")
}
}
StringDisplay.swift public class StringDisplay {
private var str:String
private var width:Int
public init(_ str:String) {
self.str = str
width = str.count
}
public func display() {
printLine()
for _ in 0...4 {
print("|" + str + "|")
printLine()
}
private func printLine() {
print("+" + String.init(repeating:"-", count:width) + "+")
}
}
Main.swift let d1:CharDisplay = CharDisplay('A')
d1.display()
let d2:StringDisplay = StringDisplay("Hello")
d2.display()
|
Template Methodパターンを使用した例 AbstractDisplay.swift public class AbstractDisplay {
internal func open() {
fatalError("open メソッドを定義してください。")
}
internal func _print() {
fatalError("_print メソッドを定義してください。")
}
internal func close() {
fatalError("close メソッドを定義してください。")
}
public func display() {
open()
for _ in 0...5 {
_print()
}
close()
}
}
CharDisplay.swift public class CharDisplay : AbstractDisplay {
private var ch:String
public init(_ ch:String) {
self.ch = ch
}
internal override func open() {
print("<<", terminator:"")
}
internal override func _print() {
print(ch, terminator:"")
}
internal override func close() {
print(">>")
}
}
StringDisplay.swift public class StringDisplay : AbstractDisplay {
private var str:String
private var width:Int
public init(_ str:String) {
self.str = str
width = str.count
}
internal override func open() {
printLine()
}
internal override func _print() {
print("|" + str + "|")
}
internal override func close() {
printLine()
}
private func printLine() {
print("+" + String.init(repeating:"-", count:width) + "+")
}
}
Main.swift var d:AbstractDisplay = CharDisplay('A')
d.display()
d = StringDisplay("Hello")
d.display()
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.kt class CharDisplay(private val ch: Char) {
fun display() {
println("<<${ch.toString().repeat(5)}>>")
}
}
StringDisplay.kt class StringDisplay(private val str: String) {
private width: Int = str.length
fun display() {
printLine()
for (i in 0..4) print("|$str|")
printLine()
}
private fun printLine() {
println("+" + "-".repeat(width) + "+")
}
}
Main.kt fun main() {
val d1 = CharDisplay('A')
d1.display()
val d2 = StringDisplay("Hello")
d2.display()
}
|
Template Methodパターンを使用した例 AbstractDisplay.kt abstract class AbstractDisplay {
abstract open()
abstract print()
abstract close()
display() {
open()
for (i in 0..4) print()
close()
}
}
CharDisplay.kt class CharDisplay(private val ch: Char) : AbstractDisplay() {
override fun open() {
print("<<")
}
override fun print() {
print(ch)
}
override fun close() {
println(">>")
}
}
StringDisplay.kt class StringDisplay(val str: String) : AbstractDisplay() {
private val width: Int = str.length
override fun open() {
printLine()
}
override fun print() {
println("|$str|")
}
override fun close() {
printLine()
}
private fun printLine() {
println("+" + "-".repeat(width) + "+")
}
}
Main.kt fun main() {
var d:AbstractDisplay = CharDisplay('A')
d.display()
d = StringDisplay("Hello")
d.display()
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.scala class CharDisplay(ch: Char) {
def display() {
System.out.println("<<" + ch.toString() * 5 + ">>")
}
}
StringDisplay.scala class StringDisplay(str: String) {
private val width: Int = str.length
def display() {
printLine()
for (_ <- 0 until 5) {
System.out.println("|" + str + "|")
}
printLine()
}
private def printLine() {
System.out.println("+" + "-" * width + "+")
}
}
Main.kt object Main {
def main(args: Array[String]) {
val d1 = new CharDisplay('A')
d1.display()
val d2 = new StringDisplay("Hello")
d2.display()
}
}
|
Template Methodパターンを使用した例 AbstractDisplay.scala abstract class AbstractDisplay {
def open()
def print()
def close()
def display() {
open()
for (_ in 0 until 5) {
print()
}
close()
}
}
CharDisplay.scala class CharDisplay(ch: Char) extends AbstractDisplay() {
def open() {
System.out.print("<<")
}
def print() {
System.out.print(ch)
}
def close() {
System.out.println(">>")
}
}
StringDisplay.scala class StringDisplay(str: String) extends AbstractDisplay() {
private val width: Int = str.length
def open() {
printLine()
}
def print() {
System.out.println("|" + str + "|")
}
def close() {
printLine()
}
private def printLine() {
System.out.println("+" + "-" *width + "+")
}
}
Main.scala object Main {
def main(args: Array[String]) {
var d: AbstractDisplay = new CharDisplay('A')
d.display()
d = new StringDisplay("Hello")
d.display()
}
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.groovy class CharDisplay {
private char ch
CharDisplay(char ch) {
this.ch = ch
}
void display() {
System.out.print("<<" + ch.toString() * 5 + ">>")
}
}
StringDisplay.groovy class StringDisplay {
private String str
private int width
StringDisplay(String str) {
this.str = str
width = str.getBytes().length
}
void display() {
printLine()
for (int _ in 0..<5)
System.out.println("|" + str + "|")
printLine()
}
private void printLine() {
System.out.print("+" + "-" * width + "+")
}
}
Main.groovy class Main {
static void main(String[] args) {
CharDisplay d1 = new CharDisplay('A' as char)
d1.display()
StringDisplay d2 = new StringDisplay("Hello")
d2.display()
}
}
|
Template Methodパターンを使用した例 AbstractDisplay.groovy abstract class AbstractDisplay {
abstract void open()
abstract void print()
abstract void close()
final void display() {
open()
for (int _ in 0..<5)
print()
close()
}
}
CharDisplay.groovy class CharDisplay extends AbstractDisplay {
private char ch;
CharDisplay(char ch) {
this.ch = ch
}
void open() {
System.out.print("<<")
}
void print() {
System.out.print(ch)
}
void close() {
System.out.println(">>")
}
}
StringDisplay.groovy class StringDisplay extends AbstractDisplay {
private String str
private int width
StringDisplay(String str) {
this.str = str
width = str.getBytes().length
}
void open() {
printLine()
}
void print() {
System.out.println("|" + str + "|")
}
void close() {
printLine()
}
private void printLine() {
System.out.print("+" + "-" * width + "+")
}
}
Main.groovy class Main {
static void main(String[] args) {
AbstractDisplay d = new CharDisplay('A' as char)
d.display()
d = new StringDisplay("Hello")
d.display()
}
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.go import (
"fmt"
"strings"
)
type CharDisplay struct {
ch rune
}
func (self *CharDisplay) Display() {
var str = string(self.ch)
fmt.Println("<<" + strings.Repeat(str, 5) + ">>")
}
func NewCharDisplay(ch rune) CharDisplay {
return &CharDisplay {
ch: ch,
}
}
StringDisplay.go import (
"fmt"
"strings"
)
type StringDisplay struct {
str string
width int
}
func (self *StringDisplay) Display() {
printLine(self.width)
for i := 0; i < 5; i++ {
fmt.Println("|" + self.str + "|")
}
printLine(self.width)
}
func printLine(width int) {
fmt.Println("+" + strings.Repeat("-", width) + "+")
}
func NewStringDisplay(str string) *StringDisplay {
return &StringDisplay {
str: str,
width: len(str),
}
}
Main.go func Main {
var d1 = NewCharDisplay('A')
d1.Display()
var d2 = NewStringDisplay("Hello")
d2.Display()
}
|
Template Methodパターンを使用した例 AbstractDisplay.go import "errors"
type IDisplay interface {
Open()
Print()
Close()
Display(IDisplay)
}
type AbstractDisplay struct {
IDisplay
}
func (*AbstractDisplay) Open() {panic(errors.New("open メソッドを定義してください。"))}
func (*AbstractDisplay) Print() {panic(errors.New("Print メソッドを定義してください。"))}
func (*AbstractDisplay) Close() {panic(errors.New("Close メソッドを定義してください。"))}
func (*AbstractDisplay) Display(display IDisplay) {
display.Open()
for i := 0; i < 5; i++ {
display.Print()
}
display.Close()
}
CharDisplay.go import "fmt"
type CharDisplay struct {
*AbstractDisplay
ch rune
}
func (*CharDisplay) Open() {
fmt.Print("<<")
}
func (*CharDisplay) Print() {
fmt.Print(string(self.ch)
}
func (*CharDisplay) Close() {
fmt.Print(">>")
}
func NewCharDisplay(ch rune) *CharDisplay {
return &CharDisplay {
ch: ch,
AbstractDisplay: new(AbstractDisplay),
}
}
StringDisplay.go import (
"fmt"
"strings"
)
type StringDisplay struct {
*AbstractDisplay
str string
width int
}
func (self *StringDisplay) Open() {
printLine(self.width)
}
func (self *StringDisplay) Print() {
fmt.Println("|" + self.str + "|")
}
func (self *StringDisplay) Close() {
printLine(self.width)
}
func printLine(width int) {
fmt.Println("+" + strings.Repeat("-", width) + "+")
}
func NewStringDisplay(str string) *StringDisplay {
return &StringDisplay {
str: str,
width: len(str),
AbstractDisplay: new(AbstractDisplay),
}
}
Main.go class main() {
var d IDisplay = NewCharDisplay('A')
d.Display(d)
d = NewStringDisplay("Hello")
d.Display(d)
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に Open()、次にPrint()を5回、最後にClose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ Open() では何をする、Print() では何をする、Close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 chardisplay.d import std.stdio, std.conv;
public class CharDisplay {
private char ch;
public this(in char ch) {
this.ch = ch;
}
public void display() {
write("<<");
foreach (int i; 0..5)
write(text(ch);
writeln(">>");
}
}
stringdisplay.d import std.stdio;
public class StringDisplay {
private string str;
private int width;
public this(in string str) {
this.str = str;
this.width = str.length;
}
public void display() {
printLine();
foreach (int i; 0..5)
write("|" ~ str ~ "|");
printLine();
}
private void printLine() {
write("+");
foreach (int i; 0..width)
write("-");
writeln("+");
}
}
main.d import chardisplay;
import stringdisplay;
public int main() {
CharDisplay d1 = new CharDisplay('A');
d1.display();
StringDisplay d2 = new StringDisplay("Hello");
d2.display();
return 0;
}
|
Template Methodパターンを使用した例 abstractdisplay.d public abstract class AbstractDisplay {
protected abstract void open();
protected abstract void print();
protected abstract void close();
public final void display() {
open();
foreach (int i; 0..5)
print();
close();
}
}
CharDisplay.java import std.stdio;
import abstractdisplay;
public class CharDisplay : AbstractDisplay {
private char ch;
public this(in char ch) {
this.ch = ch;
}
protected override void open() {
write("<<");
}
protected override void print() {
write(ch);
}
protected override void close() {
writeln(">>");
}
}
stringdisplay.d import std.stdio;
import abstractdisplay;
public class StringDisplay : AbstractDisplay {
private string str;
private int width;
public this(string str) {
this.str = str;
this.width = str.length;
}
protected override void open() {
printLine();
}
protected override void print() {
writeln("|" ~ str ~ "|");
}
protected override void close() {
printLine();
}
private void printLine() {
write("+");
foreach (int i; 0..width)
write("-");
writeln("+");
}
}
main.d import std.stdio;
import abstractdisplay;
import chardisplay;
import stringdisplay;
public int main() {
AbstractDisplay d = new CharDisplay('A');
d.display();
d = new StringDisplay("Hello");
d.display();
return 0;
}
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |
|
Template Methodパターンを使用しない例 CharDisplay.pas unit UnitCharDisplay;
interface
uses
System.StrUtils;
type
CharDisplay = class
private
var ch:Char;
public
constructor Create(ch:Char);
procedure display();
end;
implementation
constructor CharDisplay.Create(ch:Char);
begin
self.ch := ch;
end;
procedure CharDisplay.display();
begin
Writeln('<< + DupeString(ch, 5) + '>>');
end;
end.
StringDisplay.pas unit UnitStringDisplay;
interface
uses
System.StrUtils;
type
StringDisplay = class
private
var str:string;
var width:integer;
procedure printLine();
public
constructor Create(str:string);
procedure display();
end;
implementation
constructor StringDisplay.Create(str: string);
begin
self.str := str;
self.width := length(str);
end;
procedure StringDisplay.display();
var i:integer;
begin
printLine();
for i:=0 to 4 do
begin
Writeln('|' + str + '|');
end;
printLine();
end;
procedure StringDisplay.printLine();
begin
Writeln('*' + DupeString('-', width) + '*');
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitCharDisplay,
UnitStringDisplay;
var d1:CharDisplay;
var d2:StringDisplay;
begin
d1 := CharDisplay.Create('A');
d1.display();
d1.Free;
d2 := StringDisplay.Create('Hello');
d2.display();
d2.Free;
end.
|
Template Methodパターンを使用した例 AbstractDisplay.pas unit UnitAbstractDisplay;
interface
type
AbstractDisplay = class
protected
procedure open(); virtual; abstract;
procedure print(); virtual; abstract;
procedure close(); virtual; abstract;
public
procedure display();
end;
implementation
procedure AbstractDisplay.display();
var i:integer;
begin
open();
for i := 0 to 4 do
begin
print();
end;
close();
end;
end.
CharDisplay.pas unit UnitCharDisplay;
interface
uses
UnitAbstractDisplay;
type
CharDisplay = class(AbstractDisplay)
private
var ch:Char;
protected
procedure open(); override;
procedure print(); override;
procedure close(); override;
public
constructor Create(ch:Char);
end;
implementation
constructor CharDisplay.Create(ch:Char);
begin
self.ch := ch;
end;
procedure CharDisplay.open();
begin
Write('<<');
end;
procedure CharDisplay.print();
begin
Write(ch);
end;
procedure CharDisplay.close();
begin
Writeln('>>');
end;
end.
StringDisplay.pas unit UnitStringDisplay;
interface
uses
System.StrUtils,
UnitAbstractDisplay;
type
StringDisplay = class(AbstractDisplay)
private
var str:string;
var width:integer;
procedure printLine();
protected
procedure open(); override;
procedure print(); override;
procedure close(); override;
public
constructor Create(str:string);
end;
implementation
constructor StringDisplay.Create(str:string);
begin
self.str := str;
width := length(str);
end;
procedure StringDisplay.open();
begin
printLine();
end;
procedure StringDisplay.print();
begin
Writeln('|' + str + '|');
end;
procedure StringDisplay.close();
begin
printLine();
end;
procedure StringDisplay.printLine();
begin
Writeln('*' + DupeString('-', width) + '*');
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitAbstractDisplay,
UnitCharDisplay,
UnitStringDisplay;
var
d:AbstractDisplay;
begin
d := CharDisplay.Create('A');
d.display();
d.Free;
d := StringDisplay.Create('Hello');
d.display();
d.Free;
end.
| ||||||
|
CharDisplay クラスや StringDisplay クラスに、処理の枠組み(流れ)と処理内容が一緒に記述されてしまっています。
この場合、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになったらどうでしょう。 すべてのクラス(この例では2つしかないですが)を変更しなければならなくなります。 |
処理の枠組みは、スーパークラスの AbstractDisplay の display() メソッドに記述されています。 最初に open()、次にprint()を5回、最後にclose() を呼ぶというものです。 そして、AbstractDisplay を継承したサブクラス CharDisplay、StringDisplay には処理の枠組みはなく、それぞれ open() では何をする、print() では何をする、close() では何をするということが書かれているのみです。 よって、もし処理の枠組みが変更になり、表示は10回にするとか、最後の表示はいらないとかになっても、処理の枠組みを記述した AbstractDisplay のみを変更すればよいということになります。 |