Factory Methodパターン
インターフェースだけを規定、インスタンスの生成はサブクラス
Factory Method パターンは、インスタンスの生成方法に一工夫加えることで、より柔軟にインスタンスを生成することを目的とするものです。
Factory Method パターンでは、インスタンスの生成をサブクラスに行わせることで、より柔軟に生成するインスタンスを選択することが可能となります。
Template Method パターンでは、スーパークラス側でフレームワークを作り、サブクラス側で具体的な処理の実装を行いました。このパターンをインスタンス生成の場面に適用したものが、Factory Method パターンです。Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めますが、具体的なクラス名までは定めません。具体的なクラス名は全てサブクラス側で行います。これによってインスタンス生成のためのフレームワークと、実際のインスタンス生成のクラスとを分けて考えることができるようになります。
1. 利用するアルゴリズムを変更できるようにする

DBのデータに対しある演算をし、その結果を表示するようなクラスで、どのような演算かを利用時に決めたいとき、その演算のアルゴリズムを記述したメソッドをサブクラス側に実装しておきます。
例えば、集計してその結果を表示するようなクラスの場合、部とか課とかの特定の項目で集計するクラスのインスタンスを生成するメソッドをサブクラス側に記述しておきます。スーパークラスはデータを得た後、サブクラスのメソッドを呼び、その集計結果を受け取るということになります。
こうしておけば、いろいろな項目で集計する必要があっても、部で集計するサブクラス、課で集計するサブクラスというようにサブクラスを追加していくだけですみます。
このとき、スーパークラスのメソッドはどう記述すればよいでしょうか。以下の3通りが考えられます。
- 1. 抽象メソッドにする。
- サブクラスに実装しなければコンパイルエラーとなる。
- 2. デフォルト動作を実装しておく。
- サブクラスに実装しなければスーパークラスで実装された動作をする。
- 3. 例外を発生させる。
- サブクラスに実装しなければ実行時に例外が発生する。
もし、Factory Method パターンを使用しなければ、通常は if や switch などを使用して、集計する項目ごとに分岐させることになります。そして、ここで新たな項目での集計が必要になった場合は、条件式を追加しなければならなくなります。
2. 必ず一緒に利用しなければならないクラスを指定する
あるクラスと必ず一緒に利用しなければならないクラスがある場合、そのクラスのインスタンスを生成したときに自動的にもう一方のクラスのインスタンスも生成されるようにする。
例えば、もう一方のクラスのインスタンスが自動的に生成されないとしたら、これらのクラスを対として使う必要があることをプログラマーが意識してコーディングをしないといけないことになります。
プログラマーがそこまで意識してクラスを使ってくれれば良いですが、気付かなかった場合は間違ったコードがプログラムに紛れ込むことになります。これを避けるための工夫が必要になります。
Factory Method パターンは、Template Methodパターンに似ていますが、こちらはそのメソッドがインスタンス生成のみを行い、生成に重点が置かれています。
例題
区分ごとの合計値を計算するクラスを作りなさい。また、区分名の取得は、既存のクラスがあるのでそれを利用するようにしなさい。
区分2 600
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.java public abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected Data[] list = new Data[] {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
};
protected Data[] total; // 合計値
public abstract int getDivision(int n);
public abstract int getTotal(int n);
public abstract Data[] calculateTotal();
public void operation() {
total = calculateTotal();
}
}
SubTotal.java public class SubTotal extends AbstractTotal {
public Data[] calculateTotal() {
int no = list[0].no, n = 0;
Data[] total = new Data[list.length];
total[0] = new Data(no, 0);
for (int i = 0; i < list.length; i++) {
if (list[i].no != no) {
no = list[i].no;
total[++n] = new Data(no, 0);
}
total[n].value += list[i].value;
}
return total;
}
public int getDivision(int n) {
return total[n].no; // 区分
}
public int getTotal(int n) {
return total[n].value; // 合計値
}
}
Main.java public class Main {
public static void main(String[] args) {
SubTotal sub = new SubTotal();
SubDivisionName div = new SubDivisionName();
sub.operation(); // 区分ごとの合計値算
System.out.println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)); // 合計値
System.out.println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)); // 合計値
}
}
|
Factory Methodパターンを使用した例 AbstractTotal.java public abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected Data[] list = new Data[] {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
};
protected Data[] total; // 合計値
public abstract int getDivision(int n);
public abstract int getTotal(int n);
public abstract AbstractSummary getSummary();
public abstract AbstractDivisionName createDivisionName();
public void operation() {
AbstractSummary sum = getSummary();
total = sum.calculateTotal();
}
}
SubTotal.java public class SubTotal extends AbstractTotal {
public AbstractSummary getSummary() {
return new SubTotalSummary(list);
}
public int getDivision(int n) {
return total[n].no; // 区分
}
public int getTotal(int n) {
return total[n].value; // 合計値
}
public AbstractDivisionName createDivisionName() {
return new SubDivisionName();
}
}
Main.java public class Main {
public static void main(String[] args) {
SubTotal sub = new SubTotal();
AbstractDivisionName div = sub.createDivisionName();
sub.operation(); // 区分ごとの合計値算
System.out.println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)); // 合計値
System.out.println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)); // 合計値
}
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 abstractTotal.h #pragma once
#include "data.h"
#include "summary.h"
#include "abstractDivisionName.h"
class AbstractTotal
{
protected:
static Data* list[];
static int size;
Data** total; // 合計値
public:
AbstractTotal(void);
virtual ~AbstractTotal(void);
virtual int getDivision(int) = 0;
virtual int getTotal(int) = 0;
virtual Data (**calculateTotal(void)) = 0;
void operation(void);
};
abstractTotal.cpp #include "abstractTotal.h"
// 区分, 数値(実際にはDB から得る。)
Data* AbstractTotal::list[] = {
new Data(1,100),
new Data(1,500),
new Data(1,200),
new Data(2,400),
new Data(2,200)
};
int AbstractTotal::size = sizeof(list) / sizeof(list[0]);
AbstractTotal::AbstractTotal(void) {}
AbstractTotal::~AbstractTotal(void) {}
void AbstractTotal::operation(void)
{
total = calculateTotal();
}
subTotal.h #include "abstractTotal.h"
class SubTotal : public AbstractTotal
{
public:
SubTotal(void);
virtual ~SubTotal(void);
Data (**calculateTotal(void));
int getDivision(int);
int getTotal(int);
}; subTotal.cpp #include "subTotal.h"
SubTotal::SubTotal(void) {}
SubTotal::~SubTotal(void)
{
delete[] total;
}
Data (**SubTotal::calculateTotal(void))
{
int no = list[0]->no, n = 0;
total = new Data*[size];
total[0] = new Data(no, 0);
for (int i = 0; i < size; i++)
{
if (list[i]->no != no)
{
no = list[i]->no;
total[++n] = new Data(no, 0);
}
total[n]->value += list[i]->value;
}
return total;
}
int SubTotal::getDivision(int n)
{
return total[n]->no; // 区分
}
int SubTotal::getTotal(int n)
{
return total[n]->value; // 合計値
}
Main.cpp #include <iostream>
using namespace std;
#include "subTotal.h"
#include "subDivisionName.h"
int main()
{
SubTotal sub;
SubDivisionName div;
sub.operation(); // 区分ごとの合計値計算
cout << div.getName(sub.getDivision(0)) // 区分名
<< " " << sub.getTotal(0) << endl; // 合計値
cout << div.getName(sub.getDivision(1)) // 区分名
<< " " << sub.getTotal(1) << endl; // 合計値
return 0;
}
|
Factory Methodパターンを使用した例 abstractTotal.h #include "abstractsummary.h"
#include "abstractdivisionname.h"
class AbstractTotal
{
protected:
static Data* list[];
static int size;
Data** total; // 合計値
public:
AbstractTotal(void);
virtual ~AbstractTotal(void);
virtual AbstractSummary* getSummary(void) = 0;
virtual int getDivision(int) = 0;
virtual int getTotal(int) = 0;
virtual AbstractDivisionName* createDivisionName(void) = 0;
void operation(void);
}; abstractTotal.cpp #include "abstractTotal.h"
// 区分, 数値(実際にはDB から得る。)
Data* AbstractTotal::list[] = {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
};
int AbstractTotal::size = sizeof(list) / sizeof(list[0]);
AbstractTotal::AbstractTotal(void) {}
AbstractTotal::~AbstractTotal(void) {}
void AbstractTotal::operation(void) {
AbstractSummary* sum = getSummary();
total = sum->calculateTotal();
delete sum;
}
subTotal.h #include "abstractTotal.h"
class SubTotal : public AbstractTotal
{
public:
SubTotal(void);
virtual ~SubTotal(void);
AbstractSummary* getSummary();
int getDivision(int);
int getTotal(int);
AbstractDivisionName* createDivisionName(void);
}; subTotal.cpp #include "subTotal.h"
#include "subtotalsummary.h"
#include "subdivisionname.h"
SubTotal::SubTotal(void) {}
SubTotal::~SubTotal(void) {}
AbstractSummary* SubTotal::getSummary(void) {
return new SubTotalSummary(list, size);
}
int SubTotal::getDivision(int n) {
return total[n]->no; // 区分
}
int SubTotal::getTotal(int n) {
return total[n]->value; // 合計値
}
AbstractDivisionName* SubTotal::createDivisionName(void) {
return new SubDivisionName();
}
main.cpp #include <iostream>
using namespace std;
#include "subTotal.h"
#include "subdivisionname.h"
int main() {
SubTotal sub();
AbstractDivisionName* div = sub.createDivisionName();
sub.operation(); // 区分ごとの合計値計算
cout << div->getName(sub.getDivision(0)) // 区分名
<< " " << sub.getTotal(0) << endl; // 合計値
cout << div->getName(sub.getDivision(1)) // 区分名
<< " " << sub.getTotal(1) << endl; // 合計値
delete div;
return 0;
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の Operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(CreateDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.cs abstract class AbstractTotal
{
// 区分, 数値 (実際にはDBなどから数値を得る。)
protected Data[] list = new Data[] {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
};
protected Data[] total;
public abstract Data[] CalculateTotal();
public abstract int GetDivision(int n);
public abstract int GetTotal(int n);
public void Operation()
{
total = CalculateTotal();
}
}
SubTotal.cs class SubTotal : AbstractTotal
{
public override Data[] CalculateTotal()
{
int no = list[0].no;
int n = 0;
int size = list.GetLength(0);
Data[] total = new Data[size]
total[0] = new Data(no, 0);
for (int i = 0; i < size; i++)
{
if (list[i].no != no)
{
no = list[i].no;
total[++n] = new Data(no, 0);
}
total[n].value += list[i].value;
}
return total;
}
public override int GetDivision(int n)
{
return total[n].no; // 区分
}
public override int GetTotal(int n)
{
return total[n].value; // 合計値
}
}
Program.cs class Program
{
static void Main(string[] args)
{
SubTotal sub = new SubTotal();
SubDivisionName div = new SubDivisionName();
sub.Operation(); // 区分ごとの合計値計算
Console.WriteLine(div.GetName(sub.GetDivision(0)) // 区分名
+ " " + sub.GetTotal(0)); // 合計値
Console.WriteLine(div.GetName(sub.GetDivision(1)) // 区分名
+ " " + sub.GetTotal(1)); // 合計値
}
}
|
Factory Methodパターンを使用した例 AbstractTotal.cs abstract class AbstractTotal
{
// 区分, 数値 (実際にはDBなどから数値を得る。)
protected Data[] list = new Data[] {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
};
protected Data[] total;
public abstract AbstractSummary GetSummary();
public abstract int GetDivision(int n);
public abstract int GetTotal(int n);
public abstract AbstractDivisionName CreateDivisionName();
public void Operation()
{
AbstractSummary sum = GetSummary();
total = sum.CalculateTotal();
}
}
SubTotal.cs class SubTotal : AbstractTotal
{
public override AbstractSummary GetSummary()
{
return new SubTotalFactory(list);
}
public override int GetDivision(int n)
{
return total[n].no; // 区分
}
public override int GetTotal(int n)
{
return total[n].value; // 合計値
}
public override AbstractDivisionName CreateDivisionName()
{
return new SubDivisionName();
}
}
Program.cs class Program
{
static void Main(string[] args)
{
SubTotal sub = new SubTotal();
AbstractDivisionName div = sub.CreateDivisionName();
sub.Operation(); // 区分ごとの合計値計算
Console.WriteLine(div.GetName(sub.GetDivision(0)) // 区分名
+ " " + sub.GetTotal(0)); // 合計値
Console.WriteLine(div.GetName(sub.GetDivision(1)) // 区分名
+ " " + sub.GetTotal(1)); // 合計値
}
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、subTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス subTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(CreateDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.vb Public MustInherit Class AbstractTotal
' 区分, 数値 (実際にはDBなどから数値を得る。)
Protected list As Data() = {
New Data(1, 100),
New Data(1, 500),
New Data(1, 200),
New Data(2, 400),
New Data(2, 200)
}
Protected total As Data()
Public MustOverride Function CalculateTotal() As Data()
Public MustOverride Function GetDivision(n As Integer) As Integer
Public MustOverride Function GetTotal(n As Integer) As Integer
Public Sub Operation()
total = CalculateTotal()
End Sub
End Class
SubTotal.vb Public Class SubTotal
Inherits AbstractTotal
Public Overrides Function CalculateTotal() As Data()
Dim no As Integer = list(0).no
Dim n As Integer = 0
Dim size As Integer = list.GetLength(0)
total = New Data(size) {}
total(0) = New Data(no, 0)
For i As Integer = 0 To size - 1
If list(i).no <> no Then
no = list(i).no
n += 1 : total(n) = New Data(no, 0)
End If
total(n).value += list(i).value
Next
Return total
End Function
Public Overrides Function GetDivision(n As Integer) As Integer
Return total(n).no ' 区分
End Function
Public Overrides Function GetTotal(n As Integer) As Integer
Return total(n).value ' 合計値
End Function
End Class
Program.vb Module Main
Sub Main()
Dim [sub] As SubTotal = New SubTotal()
Dim div As SubDivisionName = New SubDivisionName()
[sub].Operation() ' 区分ごとの合計値計算
Console.WriteLine(div.GetName([sub].GetDivision(0)) & ' 区分名
" " & [sub].GetTotal(0)) ' 合計値
Console.WriteLine(div.GetName([sub].GetDivision(1)) & ' 区分名
" " & [sub].GetTotal(1)) ' 合計値
End Sub
End Module
|
Factory Methodパターンを使用した例 AbstractTotal.vb Public MustInherit Class AbstractTotal
' 区分, 数値 (実際にはDBなどから数値を得る。)
Protected list As Data() = {
New Data(1, 100),
New Data(1, 500),
New Data(1, 200),
New Data(2, 400),
New Data(2, 200)
}
Protected total() As Data
Public MustOverride Function GetSummary() As AbstractSummary
Public MustOverride Function GetDivision(n As Integer) As Integer
Public MustOverride Function GetTotal(n As Integer) As Integer
Public MustOverride Function CreateDivisionName() As AbstractDivisionName
Public Sub Operation()
Dim sum As AbstractSummary = GetSummary()
total = sum.CalculateTotal()
End Sub
End Class
SubTotal.vb Public Class SubTotal
Inherits AbstractTotal
Public Overrides Function GetSummary() As AbstractSummary
Return New SubTotalSummary(list)
End Function
Public Overrides Function GetDivision(n As Integer) As Integer
Return total(n).no ' 区分
End Function
Public Overrides Function GetTotal(n As Integer) As Integer
Return total(n).value ' 合計値
End Function
Public Overrides Function CreateDivisionName() As AbstractDivisionName
Return New SubDivisionName()
End Function
End Class
Program.vb Module Main
Sub Main()
Dim [sub] As SubTotal = New SubTotal()
Dim div As AbstractDivisionName = [sub].CreateDivisionName()
[sub].operation() ' 区分ごとの合計値計算
Console.WriteLine(div.GetName([sub].GetDivision(0)) & ' 区分名
" " & [sub].GetTotal(0)) ' 合計値
Console.WriteLine(div.GetName([sub].GetDivision(1)) & ' 区分名
" " & [sub].GetTotal(1)) ' 合計値
End Sub
End Module
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の Operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(CreateDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.js module.exports = class AbstractTotal {
constructor() {
// 区分 , 数値 (実際には DB などから数値を得る。)
this.list = Array.of(
{ no:1, value:100 }, { no:1, value:500 },
{ no:1, value:200 }, { no:2, value:400 },
{ no:2, value:200 }
);
}
operation() {
this.total = this.calculateTotal(); // 合計値
}
}
SubTotal.js const AbstractTotal = require("./AbstractTotal.js");
module.exports = class SubTotal extends AbstractTotal {
calculateTotal() {
let no = this.list[0].no, n = 0;
let total = new Array(this.list.length);
total[n] = {no:no, value:0};
for (let i = 0; i < this.list.length; i++) {
if (this.list[i].no != no) {
no = this.list[i].no;
total[++n] = {no:no, value:0};
}
total[n].value += this.list[i].value;
}
return total;
}
getDivision(n) {
return this.total[n].no; // 区分
}
getTotal(n) {
return this.total[n].value; // 合計値
}
}
Main.js const SubTotal = require("./SubTotal.js");
const SubDivisionName = require("./SubDivisionName.js");
let sub = new SubTotal();
let div = new SubDivisionName();
sub.operation(); // 区分ごとの合計値算
process.stdout.write(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0) + "\n"); // 合計値
process.stdout.write(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1) + "\n"); // 合計値
|
Factory Methodパターンを使用した例 AbstractTotal.js module.exports = class AbstractTotal {
constructor() {
// 区分 , 数値 (実際には DB などから数値を得る。)
this.list = Array.of(
{ no:1, value:100 }, { no:1, value:500 },
{ no:1, value:200 }, { no:2, value:400 },
{ no:2, value:200 }
);
}
getDivision() {
console.log("getDivision メソッドを定義してください。");
}
getTotal() {
console.log("getTotal メソッドを定義してください。");
}
getSummary() {
console.log("getSummary メソッドを定義してください。");
}
createDivisionName() {
console.log("createDivisionName メソッドを定義してください。");
}
operation() {
let sum = this.getSummary();
this.total = sum.calculateTotal(); // 合計値
}
}
SubTotal.js const AbstractTotal = require("./AbstractTotal.js");
const SubTotalSummary = require("./SubTotalSummary.js");
const SubDivisionName = require("./SubDivisionName.js");
module.exports = class SubTotal extends AbstractTotal {
getSummary() {
return new SubTotalSummary(this.list);
}
getDivision(n) {
return this.total[n].no; // 区分
}
getTotal(n) {
return this.total[n].value; // 合計値
}
createDivisionName() {
return new SubDivisionName();
}
}
Main.js const SubTotal = require("./SubTotal.js");
let sub = new SubTotal();
let div = sub.createDivisionName();
sub.operation(); // 区分ごとの合計値算
process.stdout.write(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0) + "\n"); // 合計値
process.stdout.write(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1) + "\n"); // 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.pm package AbstractTotal {
sub new {
my ($class) = @_;
my $this = { list => [
# 区分 , 数値 (実際には DB などから数値を得る。)
{ no => 1, value => 100 }, { no => 1, value => 500 },
{ no => 1, value => 200 }, { no => 2, value => 400 },
{ no => 2, value => 200 }
]};
return bless $this, $class;
}
sub operation {
my ($this) = @_;
@{$this->{total}} = $this->calculateTotal(); # 合計値
}
}
1;
SubTotal.pm package SubTotal {
use base qw(AbstractTotal);
sub new {
my ($class) = @_;
my $this = $class->SUPER::new();
}
sub calculateTotal {
my ($this) = @_;
my $no = $this->{list}[0]->{no};
my $n = 0;
my @total = ();
push @total, { no => $no, value => 0 };
for (my $i = 0 ; $i < @{$this->{list}} ; $i++) {
if ($this->{list}[$i]->{no} != $no) {
$no = $this->{list}[$i]->{no};
++$n;
push @total, { no => $no, value => 0 };
}
$total[$n]->{value} += $this->{list}[$i]->{value};
}
return @total;
}
sub getDivision {
my ($this, $no) = @_;
return $this->{total}[$no]->{no}; # 区分
}
sub getTotal {
my ($this, $no) = @_;
return $this->{total}[$no]->{value}; # 合計値
}
}
1;
Main.pl use lib './';
use SubTotal;
use SubDivisionName;
my $sub = new SubTotal();
my $div = new SubDivisionName();
$sub->operation(); # 区分ごとの合計値算
print $div->getName($sub->getDivision(0)) # 区分名
. " " . $sub->getTotal(0) . "\n"; # 合計値
print $div->getName($sub->getDivision(1)) # 区分名
. " " . $sub->getTotal(1) . "\n"; # 合計値
|
Factory Methodパターンを使用した例 AbstractTotal.pm package AbstractTotal {
sub new {
my ($class) = @_;
my $this = { list => [
# 区分 , 数値 (実際には DB などから数値を得る。)
{ no => 1, value => 100 }, { no => 1, value => 500 },
{ no => 1, value => 200 }, { no => 2, value => 400 },
{ no => 2, value => 200 }
]};
return bless $this, $class;
}
sub getDivision {
print "getDivision メソッドを定義してください。";
}
sub getTotal {
print "getTotal メソッドを定義してください。";
}
sub getSummary {
print "getSummary メソッドを定義してください。";
}
sub createDivisionName {
print "createDivisionName メソッドを定義してください。";
}
sub operation {
my ($this) = @_;
my $sum = $this->getSummary();
@{$this->{total}} = $sum->calculateTotal(); # 合計値
}
}
1;
SubTotal.pm package SubTotal {
use base qw(AbstractTotal);
use SubTotalSummary;
use SubDivisionName;
sub new {
my ($class) = @_;
my $this = $class->SUPER::new();
}
sub getSummary {
my ($this) = @_;
return new SubTotalSummary(\@{$this->{list}});
}
sub getDivision {
my ($this, $no) = @_;
return $this->{total}[$no]->{no}; # 区分
}
sub getTotal {
my ($this, $no) = @_;
return $this->{total}[$no]->{value}; # 合計値
}
sub createDivisionName {
return new SubDivisionName();
}
}
1;
Main.pl use lib './';
use SubTotal;
my $sub = new SubTotal();
my $div = $sub->createDivisionName();
$sub->operation(); # 区分ごとの合計値算
print $div->getName($sub->getDivision(0)) # 区分名
. " " . $sub->getTotal(0) . "\n"; # 合計値
print $div->getName($sub->getDivision(1)) # 区分名
. " " . $sub->getTotal(1) . "\n"; # 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.rb class AbstractTotal
def initialize()
# 区分 , 数値 (実際には DB などから数値を得る。)
@list = [
{ no:1, value:100 }, { no:1, value:500 },
{ no:1, value:200 }, { no:2, value:400 },
{ no:2, value:200 }
]
end
def operation()
@total = calculateTotal() # 合計値
end
end
SubTotal.rb require './AbstractTotal'
class SubTotal < AbstractTotal
def initialize()
super()
end
def calculateTotal() {
no = @list[0].fetch(:no)
n = 0
total = Array.new(@list.length);
total[n] = {no:no, value:0}
for i in 0..@list.length - 1 do
if @list[i].fetch(:no) != no then
total[n].store(:no, no)
no = @list[i].fetch(:no)
n += 1
total[n] = {no:no, value:0}
end
value = total[n].fetch(:value) + @list[i].fetch(:value)
total[n].store(:value, value)
end
return total
end
def getDivision(n)
return @total[n].fetch(:no) # 区分
end
def getTotal(n)
return @total[n].fetch(:value) # 合計値
end
end
Main.rb require './SubTotal'
require './SubDivisionName'
sub = SubTotal.new()
div = SubDivisionName.new()
sub.operation(); # 区分ごとの合計値算
puts div.getName(sub.getDivision(0)) # 区分名
+ " " + sub.getTotal(0).to_s # 合計値
puts div.getName(sub.getDivision(1)) # 区分名
+ " " + sub.getTotal(1).to_s # 合計値
|
Factory Methodパターンを使用した例 AbstractTotal.rb class AbstractTotal
def initialize()
# 区分 , 数値 (実際には DB などから数値を得る。)
@list = [
{ no:1, value:100 }, { no:1, value:500 },
{ no:1, value:200 }, { no:2, value:400 },
{ no:2, value:200 }
]
end
def getDivision()
puts "getDivision メソッドを定義してください。"
end
def getTotal()
def "getTotal メソッドを定義してください。"
end
def getSummary()
def "getSummary メソッドを定義してください。"
end
def createDivisionName()
def "createDivisionName メソッドを定義してください。"
end
def operation()
sum = this.getSummary()
@total = sum.calculateTotal() # 合計値
end
end
SubTotal.js require './AbstractTotal'
require './SubTotalSummary'
require './SubDivisionName'
class SubTotal < AbstractTotal
def initialize()
super()
end
def getSummary()
return SubTotalSummary.new(@list)
end
def getDivision(n) {
return @total[n].fetch(:no) # 区分
end
def getTotal(n)
return @total[n].fetch(:value) # 合計値
end
def createDivisionName()
return SubDivisionName.new()
end
end
Main.rb require './SubTotal'
sub = SubTotal.new()
div = sub.createDivisionName()
sub.operation() # 区分ごとの合計値算
puts div.getName(sub.getDivision(0)) # 区分名
+ " " + sub.getTotal(0).to_s # 合計値
puts div.getName(sub.getDivision(1)) # 区分名
+ " " + sub.getTotal(1).to_s # 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.py from abc import ABCMeta, abstractmethod
class AbstractTotal(metaclass=ABCMeta):
def __init__(self):
# 区分 , 数値 (実際には DB などから数値を得る。)
this.list = [
{ no:1, value:100 }, { no:1, value:500 },
{ no:1, value:200 }, { no:2, value:400 },
{ no:2, value:200 }
]
@abstractmethod
def getDivision(self, n):
pass
@abstractmethod
def getTotal(self, n):
pass
@abstractmethod
def calculateTotal(self):
pass
def operation(self):
self.total = self.calculateTotal() # 合計値
SubTotal.py from AbstractTotal import AbstractTotal
class SubTotal(AbstractTotal):
def calculateTotal(self):
no = self.list[0]["no"]
n = 0
total = list(range(len(self.list)))
total[n] = {"no":no, "value":0}
for i in range(len(self.list)):
if self.list[i]["no"] != no:
no = self.list[i]["no"]
n += 1
total[n] = {"no":no, "value":0}
total[n]["value"] += self.list[i]["value"]
return total
def getDivision(n):
return self.total[n]["no"] # 区分
def getTotal(n):
return self.total[n]["value"] # 合計値
Main.py from SubTotal import SubTotal
from SubDivisionName import SubDivisionName
sub = SubTotal()
div = SubDivisionName()
sub.operation() # 区分ごとの合計値算
print(div.getName(sub.getDivision(0)) # 区分名
+ " " + str(sub.getTotal(0))) # 合計値
print(div.getName(sub.getDivision(1)) # 区分名
+ " " + str(sub.getTotal(1))) # 合計値
|
Factory Methodパターンを使用した例 AbstractTotal.py from abc import ABCMeta, abstractmethod
class AbstractTotal(metaclass=ABCMeta):
def __init__(self):
# 区分 , 数値 (実際には DB などから数値を得る。)
self.list = [
{ "no":1, "value":100 }, { "no":1, "value":500 },
{ "no":1, "value":200 }, { "no":2, "value":400 },
{ "no":2, "value":200 }
]
@abstractmethod
def getDivision(self, n):
pass
@abstractmethod
def getTotal(self, n):
pass
@abstractmethod
def getSummary(self):
pass
@abstractmethod
def createDivisionName(self):
pass
def operation(self):
sum = self.getSummary()
self.total = sum.calculateTotal() # 合計値
SubTotal.py from AbstractTotal import AbstractTotal
from SubTotalSummary import SubTotalSummary
from SubDivisionName import SubDivisionName
class SubTotal(AbstractTotal):
def getSummary(self):
return SubTotalSummary(self.list)
def getDivision(self, n):
return self.total[n]["no"] # 区分
def getTotal(self, n):
return self.total[n]["value"] # 合計値
def createDivisionName(self):
return SubDivisionName()
Main.py from SubTotal import SubTotal
from SubDivisionName import SubDivisionName
sub = SubTotal()
div = sub.createDivisionName()
sub.operation() # 区分ごとの合計値算
print(div.getName(sub.getDivision(0)) # 区分名
+ " " + str(sub.getTotal(0))) # 合計値
print(div.getName(sub.getDivision(1)) # 区分名
+ " " + str(sub.getTotal(1))) # 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.php <?php
require_once('Data.php');
abstract class AbstractTotal {
public function __construct() {
// 区分 , 数値 (実際には DB などから数値を得る。)
$this->list = array(
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
);
}
public abstract function getDivision($n);
public abstract function getTotal($n);
public abstract function calculateTotal();
public function operation() {
$this->total = $this->calculateTotal();
}
}
?>
SubTotal.php <?php
require_once('AbstractTotal.php');
class SubTotal extends AbstractTotal {
public function __construct() {
parent::__construct();
}
public function calculateTotal() {
$no = $this->list[0]->no;
$n = 0;
$total = array();
$total[0] = new Data($no, 0);
for ($i = 0; $i < count($this->list); $i++) {
if ($this->list[$i].no != $no) {
$no = $this->list[$i]->no;
$total[++$n] = new Data($no, 0);
}
$total[$n]->value += $this->list[$i]->value;
}
return $total;
}
public function getDivision($n) {
return $this->total[$n]->no; // 区分
}
public function getTotal($n) {
return $this->total[$n]->value; // 合計値
}
}
?>
Main.php <?php
require_once('SubTotal.php');
require_once('SubDivisionName.php');
$sub = new SubTotal();
$div = new SubDivisionName();
$sub->operation(); // 区分ごとの合計値算
print $div->getName($sub->getDivision(0)) // 区分名
. " " . sub.getTotal(0) . "\n"; // 合計値
print $div->getName($sub->getDivision(1)) // 区分名
. " " . sub->getTotal(1) . "\n"; // 合計値
?>
|
Factory Methodパターンを使用した例 AbstractTotal.php <?php
require_once('Data.php');
abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
public function __construct() {
$this->list = array(
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
);
}
public abstract function getDivision($n);
public abstract function getTotal($n);
public abstract function getSummary();
public abstract function createDivisionName();
public void operation() {
$sum = getSummary();
$this->total = $sum->calculateTotal();
}
}
?>
SubTotal.php <?php
require_once('AbstractTotal.php');
require_once('SubTotalSummary.php');
require_once('SubDivisionName.php');
class SubTotal extends AbstractTotal {
public function __construct() {
parent::__construct();
}
public function getSummary() {
return new SubTotalSummary($this->list);
}
public function getDivision($n) {
return $this->$total[$n]->no; // 区分
}
public function getTotal($n) {
return $this->total[$n]->value; // 合計値
}
public function createDivisionName() {
return new SubDivisionName();
}
}
?>
Main.java <?php
require_once('SubTotal.php');
require_once('SubDivisionName.php');
$sub = new SubTotal();
$div = $sub->createDivisionName();
$sub->operation(); // 区分ごとの合計値算
print $div->getName($sub->getDivision(0))// 区分名
. " " . $sub->getTotal(0) . "\n"; // 合計値
print $div->getName($sub->getDivision(1)) // 区分名
. " " . $sub->getTotal(1) . "\n"; // 合計値
?>
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.ts import {Data} from "./Data";
export
abstract class AbstractTotal {
protected list:Array<Data>;
protected total:Array<Data>;
public constructor() {
this.list = Array.of(
// 区分 , 数値 (実際には DB などから数値を得る。)
new Data(1, 100), new Data(1, 500), new Data(1, 200),
new Data(2, 400), new Data(2, 200)
);
}
public operation():void {
this.total = this.calculateTotal(); // 合計値
}
public abstract calculateTotal():Array<Data>;
}
SubTotal.ts import {Data} from "./Data";
import {AbstractTotal} from "./AbstractTotal";
export
class SubTotal extends AbstractTotal {
public calculateTotal():Array<Data> {
let no:number = list[0].no;
let n:number = 0;
let total:Array<Data> = new Array<Data>(list.length);
total[0] = new Data(no, 0);
for (i:number = 0; i < this.list.length; i++) {
if (this.list[i].no != no) {
no = this.list[i].no;
total[++n] = new Data(no, 0);
}
total[n].value += this.list[i].value;
}
return total;
}
public getDivision(n:number):number {
return this.total[n].no; // 区分
}
public getTotal(n:number):number {
return this.total[n].value; // 合計値
}
}
Main.ts import {SubTotal} from "./SubTotal";
import {SubDivisionName} from "./SubDivisionName";
let sub:SubTotal = new SubTotal();
let div:SubDivisionName = new SubDivisionName();
sub.operation(); // 区分ごとの合計値算
process.stdout.write(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0) + "\n"); // 合計値
process.stdout.write(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1) + "\n"); // 合計値
}
}
|
Factory Methodパターンを使用した例 AbstractTotal.ts import {Data} from "./Data";
import {AbstractDivisionName} from "./AbstractDivisionName";
import {AbstractSummary} from "./AbstractSummary";
export
abstract class AbstractTotal {
protected list:Array<Data>;
protected total:Array<Data>;
public constructor() {
this.list = Array.of(
// 区分 , 数値 (実際には DB などから数値を得る。)
new Data(1, 100), new Data(1, 500), new Data(1, 200),
new Data(2, 400), new Data(2, 200)
);
}
public abstract getDivision(n:number):number;
public abstract getTotal(n:number):number;
public abstract getSummary():AbstractSummary;
public abstract createDivisionName():AbstractDivisionName;
public operation():void {
let sum:AbstractSummary = this.getSummary();
this.total = sum.calculateTotal();
}
}
SubTotal.ts import {AbstractTotal} from "./AbstractTotal";
import {AbstractSummary} from "./AbstractSummary";
import {AbstractDivisionName} from "./AbstractDivisionName";
import {SubTotalSummary} from "./SubTotalSummary";
import {SubDivisionName} from "./SubDivisionName";
export
class SubTotal extends AbstractTotal {
public getSummary():AbstractSummary {
return new SubTotalSummary(this.list);
}
public getDivision(n:number):number {
return this.total[n].no; // 区分
}
public getTotal(n:number):number {
return this.total[n].value; // 合計値
}
public createDivisionName():AbstractDivisionName {
return new SubDivisionName();
}
}
Main.ts import {SubTotal} from "./SubTotal";
import {AbstractDivisionName} from "./AbstractDivisionName";
let sub:SubTotal = new SubTotal();
let div:AbstractDivisionName = sub.createDivisionName();
sub.operation(); // 区分ごとの合計値算
process.stdout.write(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0) + "\n"); // 合計値
process.stdout.write(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1) + "\n"); // 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.swift public class AbstractTotal {
internal var list:[Data] = [
// 区分 , 数値 (実際には DB などから数値を得る。)
Data(1, 100), Data(1, 500), Data(1, 200),
Data(2, 400), Data(2, 200)
]
internal var total:[Data] = []
public func operation() {
total = calculateTotal() // 合計値
}
public calculateTotal() -> [Data] {
fatalError("calculateTotal メソッドを定義してください。")
}
}
SubTotal.swift public class SubTotal : AbstractTotal {
public override func calculateTotal() -> [Data] {
let no:Int = list[0].no
let n:Int = 0;
let total:[Data] = []
total.append(Data(no, 0))
for i in 0..<list.count {
if list[i].no != no {
no = list[i].no
n += 1
total.append(Data(no, 0))
}
total[n].value += list[i].value
}
return total
}
public func getDivision(_ n:Int) -> Int {
return total[n].no // 区分
}
public func getTotal(_ n:Int) -> Int {
return total[n].value // 合計値
}
}
Main.swift let sub:SubTotal = SubTotal()
let div:SubDivisionName = SubDivisionName()
sub.operation() // 区分ごとの合計値算
print(div.getName(sub.getDivision(0)) // 区分名
+ " " + String(sub.getTotal(0))) // 合計値
print(div.getName(sub.getDivision(1)) // 区分名
+ " " + String(sub.getTotal(1))) // 合計値
|
Factory Methodパターンを使用した例 AbstractTotal.swift public class AbstractTotal {
internal var list:[Data] = [
// 区分 , 数値 (実際には DB などから数値を得る。)
Data(1, 100), Data(1, 500), Data(1, 200),
Data(2, 400), Data(2, 200)
]
internal var total:[Data] = []
public func getDivision(_ n:Int) -> Int {
fatalError("getDivision メソッドを定義してください。")
}
public func getTotal(_ n:Int) -> Int {
fatalError("getTotal メソッドを定義してください。")
}
public func getSummary() -> AbstractSummary {
fatalError("getSummary メソッドを定義してください。")
}
public func createDivisionName() -> AbstractDivisionName {
fatalError("createDivisionName メソッドを定義してください。")
}
public func operation() {
let sum:AbstractSummary = getSummary()
total = sum.calculateTotal() // 合計値
}
}
SubTotal.swift public class SubTotal : AbstractTotal {
public override func getSummary():AbstractSummary {
return SubTotalSummary(list)
}
public override func getDivision(_ n:Int) -> Int {
return total[n].no // 区分
}
public override func getTotal(_ n:Int) -> Int {
return total[n].value // 合計値
}
public override func createDivisionName() -> AbstractDivisionName {
return SubDivisionName()
}
}
Main.swift let sub:SubTotal = SubTotal()
let div:AbstractDivisionName = sub.createDivisionName()
sub.operation() // 区分ごとの合計値算
print(div.getName(sub.getDivision(0)) // 区分名
+ " " + String(sub.getTotal(0)) // 合計値
print(div.getName(sub.getDivision(1)) // 区分名
+ " " + String(sub.getTotal(1)) // 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.kt abstract class AbstractTotal() {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected var list = arrayOf(
Data(1, 100), Data(1, 500), Data(1, 200),
Data(2, 400), Data(2, 200)
)
protected lateinit var total: Array<Data?> // 合計値
abstract fun getDivision(n: Int): Int
abstract fun getTotal(n: Int): Int
abstract fun calculateTotal(): Array<Data?>
internal fun operation() {
total = calculateTotal() // 合計値
}
}
SubTotal.kt class SubTotal() : AbstractTotal() {
override fun calculateTotal(): Array<Data?> {
var no: Int = list[0].no
var n: Int = 0
val total = arrayOfNulls<Data>(list.size)
total[0] = Data(no, 0)
for (data in list) {
if (data.no != no) {
no = data.no
total[++n] = Data(no, 0)
}
total[n].value += data.value
}
return total
}
override fun getDivision(n: Int): Int = total[n]!!.no // 区分
override fun getTotal(n: Int): Int = total[n]!!.value // 合計値
}
}
Main.kt fun main() {
val sub = SubTotal()
val div = SubDivisionName()
sub.operation() // 区分ごとの合計値算
println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)) // 合計値
println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)) // 合計値
}
|
Factory Methodパターンを使用した例 AbstractTotal.kt abstract class AbstractTotal {
protected list = arrayof(
// 区分 , 数値 (実際には DB などから数値を得る。)
Data(1, 100), Data(1, 500), Data(1, 200),
Data(2, 400), Data(2, 200)
)
internal lateinit var total: Array<Data?>
abstract getDivision(n: Int): Int
abstract getTotal(n: Int): Int
abstract getSummary(): AbstractSummary
abstract createDivisionName(): AbstractDivisionName
fun operation() {
val sum: AbstractSummary = getSummary()
total = sum.calculateTotal()
}
}
SubTotal.kt class SubTotal() : AbstractTotal() {
override fun getSummary(): AbstractSummary {
return SubTotalSummary(list)
}
override fun getDivision(n: Int): Int = total[n]!!.no // 区分
override fun getTotal(n: Int): Int = total[n]!!.value // 合計値
override fun createDivisionName():AbstractDivisionName {
return SubDivisionName()
}
}
Main.kt fun main() {
val sub: SubTotal = SubTotal()
val div: AbstractDivisionName = sub.createDivisionName()
sub.operation() // 区分ごとの合計値算
println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)) // 合計値
println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)) // 合計値
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.scala abstract class AbstractTotal() {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected val list = Seq(
new Data(1, 100), new Data(1, 500), new Data(1, 200),
new Data(2, 400), new Data(2, 200)
)
protected var total: Array[Data] = null // 合計値
def getDivision(n: Int): Int
def getTotal(n: Int): Int
def calculateTotal(): Array[Data]
def operation() {
total = calculateTotal() // 合計値
}
}
SubTotal.scala class SubTotal() extends AbstractTotal() {
def calculateTotal(): Array[Data] = {
var no: Int = list[0].no
var n: Int = 0
val total = new Array[Data](list.length)
total[0] = new Data(no, 0)
for (data: Data <- list) {
if (data.no != no) {
no = data.no
n += 1
total[n] = new Data(no, 0)
}
total(n).value += data.value
}
total
}
def getDivision(n: Int): Int = total(n).no // 区分
def getTotal(n: Int): Int = total(n).value // 合計値
}
}
Main.scala object Main {
def main(args: Array[String]) {
val sub = new SubTotal()
val div = new SubDivisionName()
sub.operation() // 区分ごとの合計値算
System.out.println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)) // 合計値
System.out.println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)) // 合計値
}
}
|
Factory Methodパターンを使用した例 AbstractTotal.scala abstract class AbstractTotal {
protected list = Seq(
// 区分 , 数値 (実際には DB などから数値を得る。)
new Data(1, 100), new Data(1, 500), new Data(1, 200),
new Data(2, 400), new Data(2, 200)
)
protected var total: Array[Data] = null
def getDivision(n: Int): Int
def getTotal(n: Int): Int
def getSummary(): AbstractSummary
def createDivisionName(): AbstractDivisionName
def operation() {
val sum: AbstractSummary = getSummary()
total = sum.calculateTotal()
}
}
SubTotal.scala class SubTotal() extends AbstractTotal() {
def getSummary() = new SubTotalSummary(list)
def getDivision(n: Int): Int = total(n).no // 区分
def getTotal(n: Int): Int = total(n).value // 合計値
def createDivisionName():AbstractDivisionName = new SubDivisionName()
}
Main.scala object Main {
def main(args: Array[String]) {
val sub = new SubTotal()
val div: AbstractDivisionName = sub.createDivisionName()
sub.operation() // 区分ごとの合計値算
System.out.println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)) // 合計値
System.out.println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)) // 合計値
}
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.groovy abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected Data[] list = new Data[] {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
}
protected Data[] total // 合計値
abstract int getDivision(int n)
abstract int getTotal(int n)
abstract Data[] calculateTotal()
void operation() {
total = calculateTotal()
}
}
SubTotal.groovy class SubTotal extends AbstractTotal {
Data[] calculateTotal() {
int no = list[0].no, n = 0
Data[] total = new Data[list.length]
total[0] = new Data(no, 0)
for (Data data in list) {
if (data.no != no) {
no = data.no
total[++n] = new Data(no, 0)
}
total[n].value += list[i].value
}
return total
}
int getDivision(int n) {
return total[n].no // 区分
}
int getTotal(int n) {
return total[n].value // 合計値
}
}
Main.groovy class Main {
static void main(String[] args) {
SubTotal sub = new SubTotal()
SubDivisionName div = new SubDivisionName()
sub.operation() // 区分ごとの合計値算
System.out.println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)) // 合計値
System.out.println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)) // 合計値
}
}
|
Factory Methodパターンを使用した例 AbstractTotal.groovy abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected Data[] list = new Data[] {
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
}
protected Data[] total // 合計値
abstract int getDivision(int n)
abstract int getTotal(int n)
abstract AbstractSummary getSummary()
abstract AbstractDivisionName createDivisionName()
void operation() {
AbstractSummary sum = getSummary()
total = sum.calculateTotal()
}
}
SubTotal.groovy class SubTotal extends AbstractTotal {
AbstractSummary getSummary() {
return new SubTotalSummary(list)
}
int getDivision(int n) {
return total[n].no // 区分
}
int getTotal(int n) {
return total[n].value // 合計値
}
AbstractDivisionName createDivisionName() {
return new SubDivisionName()
}
}
Main.groovy class Main {
public static void main(String[] args) {
SubTotal sub = new SubTotal()
AbstractDivisionName div = sub.createDivisionName()
sub.operation() // 区分ごとの合計値算
System.out.println(div.getName(sub.getDivision(0)) // 区分名
+ " " + sub.getTotal(0)) // 合計値
System.out.println(div.getName(sub.getDivision(1)) // 区分名
+ " " + sub.getTotal(1)) // 合計値
}
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.go import (
"fmt"
"os"
)
type ITotal interface {
CalculateTotal() []*Data
}
type AbstractTotal struct {
ITotal
list []*Data
total []*Data
}
func (*AbstractTotal) GetDivision(int) int {
panic(errors.New("GetDivision メソッドを定義してください。"))
return 0
}
func (*AbstractTotal) GetTotal(int) int {
panic(errors.New("GetTotal メソッドを定義してください。"))
return 0
}
func (*AbstractTotal) CalculateTotal() []*Data {
panic(errors.New("CalculateTotal メソッドを定義してください。"))
return nil
}
func (self *AbstractTotal) Operation(total ITotal) {
self.total = total.CalculateTotal()
}
func NewAbstractTotal() *AbstractTotal {
return &AbstractTotal {
list: []*Data {
// 区分 , 数値 (実際には DB などから数値を得る。)
NewData(1, 100),
NewData(1, 500),
NewData(1, 200),
NewData(2, 400),
NewData(2, 200),
},
}
}
SubTotal.go type SubTotal struct {
*AbstractTotal
}
func (self *SubTotal) CalculateTotal() []*Data {
var no = self.list[0].no
var n = 0
self.total = append(self.total, NewData(no, 0))
for i:=0; i<len(self.list); i++ {
var data = self.list[i]
if data.no != no {
no = data.no
self.total = append(self.total, NewData(no, 0))
n++
}
self.total[n].total += data.total
}
return self.total
}
func (self *SubTotal) GetDivision(n int) int {
return self.total[n].no // 区分
}
func (self *SubTotal) GetTotal(n int) int {
return self.total[n].value // 合計値
}
func NewSubTotal() *SubTotal {
return &SubTotal{
NewAbstractTotal(),
}
}
Main.go import (
"fmt"
"strconv"
)
type main() {
var sub = NewSubTotal()
var div = NewSubDivisionName()
sub.operation() // 区分ごとの合計値算
fmt.Println(div.GetName(sub.GetDivision(0)) // 区分名
+ " " + sub.GetTotal(0)) // 合計値
fmt.Println(div.GetName(sub.GetDivision(1)) // 区分名
+ " " + sub.GetTotal(1)) // 合計値
}
|
Factory Methodパターンを使用した例 AbstractTotal.go import "errors"
type ITotal interface {
GetDivision(int) int
GetTotal(int) int
CreateDivisionName() IDivisionName
GetSummary() ISummary
}
type IAbstractTotal interface {
ITotal
Operation(IAbstractTotal)
}
type AbstractTotal struct {
IAbstractTotal
list []*Data
total []*Data // 合計値
}
func (*AbstractTotal) GetDivision(int) int {
panic(errors.New("エラー:GetDivision メソッドを定義する必要があります。"))
return 0
}
func (*AbstractTotal) GetTotal(int) int {
panic(errors.New("エラー:GetTotal メソッドを定義する必要があります。"))
return 0
}
func (*AbstractTotal) GetSummary() ISummary {
panic(errors.New("エラー:GetSummary メソッドを定義する必要があります。"))
return nil
}
func (*AbstractTotal) CreateDivisionName() IDivisionName {
panic(errors.New("エラー:CreateDivisionName メソッドを定義する必要があります。"))
return nil
}
func (*AbstractTotal) Operation(total IAbstractTotal) {
var sum = total.GetSummary()
self.total = sum.CalculateTotal()
}
func NewAbstractTotal() *AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
return &AbstractTotal {
list: []*Data{
NewData(1, 100),
NewData(1, 500),
NewData(1, 200),
NewData(2, 400),
NewData(2, 200),
},
}
}
SubTotal.go type SubTotal struct {
*AbstractTotal
}
func (self *SubTotal) GetSummary() ISummary {
return NewSubTotalSummary(self.list)
}
func (self *SubTotal) GetDivision(n int) {
return self.total[n].no // 区分
}
func (self *SubTotal) GetTotal(n int) {
return self.total[n].value // 合計値
}
func (self *SubTotal) CreateDivisionName() IDivisionName {
return new SubDivisionName()
}
func NewSubTotal() IAbstractTotal {
var s IAbstractTotal
s = &SubTotal {
AbstractTotal: NewAbstractTotal(),
}
return s
}
Main.go import (
"fmt"
"strconv"
)
func main {
var sub = NewSubTotal()
var div = sub.CreateDivisionName()
sub.operation() // 区分ごとの合計値算
fmt.Println(div.GetName(sub.GetDivision(0)) // 区分名
+ " " + sub.GetTotal(0)) // 合計値
fmt.Println(div.GetName(sub.GetDivision(1)) // 区分名
+ " " + sub.GetTotal(1)) // 合計値
}
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 abstracttotal.d import data;
public abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected Data[] list = [
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
];
protected Data[] total; // 合計値
public abstract int getDivision(in int n);
public abstract int getTotal(in int n);
public abstract Data[] calculateTotal();
public void operation() {
total = calculateTotal();
}
}
subtotal.d import abstracttotal;
import data;
public class SubTotal : AbstractTotal {
public override Data[] calculateTotal() {
int no = list[0].no, n = 0;
Data[] total = new Data[list.length];
total[0] = new Data(no, 0);
foreach (int i; 0..list.length) {
if (list[i].no != no) {
no = list[i].no;
total[++n] = new Data(no, 0);
}
total[n].value += list[i].value;
}
return total;
}
public override int getDivision(in int n) {
return total[n].no; // 区分
}
public override int getTotal(in int n) {
return total[n].value; // 合計値
}
}
main.d import subtotal;
import subdivisionname;
public int main() {
SubTotal sub = new SubTotal();
SubDivisionName div = new SubDivisionName();
sub.operation(); // 区分ごとの合計値算
printfln("%s %d", div.getName(sub.getDivision(0)), // 区分名
sub.getTotal(0)); // 合計値
printfln("%s %d", div.getName(sub.getDivision(1)), // 区分名
sub.getTotal(1)); // 合計値
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std;
import std.windows.charset;
import core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
Factory Methodパターンを使用した例 abstracttotal.d import data;
import abstractsummary;
import abstractdivisionname;
public abstract class AbstractTotal {
// 区分 , 数値 (実際には DB などから数値を得る。)
protected Data[] list = new Data[] [
new Data(1, 100),
new Data(1, 500),
new Data(1, 200),
new Data(2, 400),
new Data(2, 200)
];
protected Data[] total; // 合計値
public abstract int getDivision(in int n);
public abstract int getTotal(in int n);
public abstract AbstractSummary getSummary();
public abstract AbstractDivisionName createDivisionName();
public void operation() {
AbstractSummary sum = getSummary();
total = sum.calculateTotal();
}
}
subtotal.d import abstracttotal;
import abstractsummary;
import subtotalsummary;
import abstractdivisionname;
import subdivisionname;
public class SubTotal : AbstractTotal {
public override AbstractSummary getSummary() {
return new SubTotalSummary(list);
}
public override int getDivision(in int n) {
return total[n].no; // 区分
}
public override int getTotal(in int n) {
return total[n].value; // 合計値
}
public override AbstractDivisionName createDivisionName() {
return new SubDivisionName();
}
}
main.d import subtotal;
import subdivisionname;
public int main() {
SubTotal sub = new SubTotal();
AbstractDivisionName div = sub.createDivisionName();
sub.operation(); // 区分ごとの合計値算
printfln("%s %d", div.getName(sub.getDivision(0)), // 区分名
sub.getTotal(0)); // 合計値
printfln("%s %d", div.getName(sub.getDivision(1)), // 区分名
sub.getTotal(1)); // 合計値
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std;
import std.windows.charset;
import core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |
既存クラス
|
Factory Methodパターンを使用しない例 AbstractTotal.pas unit UnitAbstractTotal;
interface
uses
UnitAbstractDivisionName,
UnitData;
type
TArrayOfData = array of Data;
AbstractTotal = class
protected
var list:TArrayOfData;
var total:TArrayOfData;
public
constructor Create();
destructor Destroy(); override;
function getDivision(n:integer):integer; virtual; abstract;
function getTotal(n:integer):integer; virtual; abstract;
function calculateTotal():TArrayOfData; virtual; abstract;
procedure operation();
end;
implementation
constructor AbstractTotal.Create();
begin
list := [
Data.Create(1, 100),
Data.Create(1, 500),
Data.Create(1, 200),
Data.Create(2, 400),
Data.Create(2, 200)
];
end;
destructor AbstractTotal.Destroy();
var _data:Data;
begin
for _data in list do begin
_data.Free;
end;
end;
procedure AbstractTotal.operation();
begin
total := calculateTotal();
end;
end.
SubTotal.pas unit UnitSubTotal;
interface
uses
UnitAbstractTotal,
UnitData;
type
SubTotal = class(AbstractTotal)
public
function calculateTotal():TArrayOfData; override;
function getDivision(n:integer):integer; override;
function getTotal(n:integer):integer; override;
end;
implementation
function SubTotal.calculateTotal(): TArrayOfData;
var total:TArrayOfData;
var no:integer;
var n:integer;
var i:integer;
begin
no := list[0].no;
n := 0;
SetLength(total, Length(list));
total[0] := Data.Create(no, 0);
for i := 0 to Length(list) do
begin
if list[i].no <> no then
begin
no := list[i].no;
INC(n);
SetLength(total, n + 1);
total[n] := Data.Create(no, 0);
end;
total[n].value := total[n].value + list[i].value;
end;
Result := total;
end;
function SubTotal.getDivision(n:integer):integer;
begin
Result := total[n].no; // 区分
end;
function SubTotal.getTotal(n:integer):integer;
begin
Result := total[n].value; // 合計値
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitSubDivisionName,
UnitSubTotal;
var
sub:SubTotal;
divName:SubDivisionName;
begin
sub := SubTotal.Create();
divName := SubDivisionName.Create();
sub.operation(); // 区分ごとの合計値算
Writeln(Format('%s %d', [divName.getName(sub.getDivision(0)), // 区分名
sub.getTotal(0)])); // 合計値
Writeln(Format('%s %d', [divName.getName(sub.getDivision(1)), // 区分名
sub.getTotal(1)])); // 合計値
sub.Free;
end.
|
Factory Methodパターンを使用した例 AbstractTotal.pas unit UnitAbstractTotal;
interface
uses
UnitAbstractDivisionName,
UnitData;
type
TArrayOfData = array of Data;
AbstractTotal = class
protected
var list:TArrayOfData;
var total:TArrayOfData;
public
constructor Create();
destructor Destroy(); override;
function getDivision(n:integer):integer; virtual; abstract;
function getTotal(n:integer):integer; virtual; abstract;
function calculateTotal(): TArrayOfData; virtual; abstract;
procedure operation();
end;
implementation
constructor AbstractTotal.Create();
begin
list := [
Data.Create(1, 100),
Data.Create(1, 500),
Data.Create(1, 200),
Data.Create(2, 400),
Data.Create(2, 200)
];
end;
destructor AbstractTotal.Destroy();
var _data:Data;
begin
for _data in list do begin
_data.Free;
end;
end;
procedure AbstractTotal.operation();
var sum: AbstractSummary;
begin
sum := getSummary();
total := sum.calculateTotal();
end;
end.
SubTotal.pas unit UnitSubTotal;
interface
uses
UnitAbstractTotal,
UnitAbstractSummary,
UnitAbstractDivisionName,
UnitSubTotalSummary,
UnitSubDivisionName;
type
SubTotal = class(AbstractTotal)
public
function getSummary():AbstractSummary; override;
function getDivision(n:integer):integer; override;
function getTotal(n:integer):integer; override;
function createDivisionName():AbstractDivisionName; override;
end;
implementation
function SubTotal.getSummary():AbstractSummary;
begin
Result := SubTotalSummary.Create(list);
end;
function SubTotal.getDivision(n:integer):integer;
begin
Result := total[n].no; // 区分
end;
function SubTotal.getTotal(n:integer):integer;
begin
Result := total[n].value; // 合計値
end;
function SubTotal.createDivisionName():AbstractDivisionName;
begin
Result := SubDivisionName.Create();
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitAbstractDivisionName,
UnitSubTotal;
var
sub:SubTotal;
divName:AbstractDivisionName;
begin
sub := SubTotal.Create();
divName := sub.createDivisionName();
sub.operation(); // 区分ごとの合計値算
Writeln(Format('%s %d', [divName.getName(sub.getDivision(0)), // 区分名
sub.getTotal(0)])); // 合計値
Writeln(Format('%s %d', [divName.getName(sub.getDivision(1)), // 区分名
sub.getTotal(1)])); // 合計値
sub.Free;
end.
|
|
Template Method パターンで作成しました。区分ごとの合計値を求める、同じ処理をする既存クラス(SubTotalSummary クラス)があっても、利用していません。ソースをコピーして貼り付けているわけです。 そうすると、元のクラスにバグがあったりすると、コピーしたすべてのクラスで修正しなければならなくなるわけです。すべてのクラスが見つかればいいですが、見つからず修正されないまま放置されることになります。 また、SubTotal クラスと SubDivisionName クラスは必ず一緒に利用しなければならないとなっています。つまり、SubTotal クラスを利用して合計値を計算し、SubDivisionName クラスを利用して区分の名称を取り出しています。 こういった、一緒に使わなければならないクラスの組合せが多かったり、一緒に使うクラスの数が何十もあったのではとても覚え切れません。 |
スーパークラス AbstractTotal の operation では、処理の枠組みが記述されています。そして、サブクラス SubTotal では、処理の内容が書かれています。前に説明しました Template Method パターンでも、スーパークラス側で処理の枠組みを作り,サブクラス側で具体的な処理の実装を行いました。つまり、Factory Method パターンは Template Method パターンと同じです。Template Method パターンをインスタンス生成の場面に適用したものが、Factory Method パターンというわけです。 Factory Method パターンでは、インスタンスの作り方をスーパークラス側で定めるが,具体的なクラス名までは定めません。具体的な肉付け(ここでは、既存クラスの SubTotalSummary クラスを利用するということ)は全て SubTotal というサブクラス側で行います。これによってインスタンス生成のための枠組みと、実際のインスタンス生成のクラスとを分けて考えることができます。 したがって、合計値を求める別の方法があったとしても、別の方法を行うクラスのインスタンスを生成するサブクラスを追加するだけで済みます。これが、1の「利用するアルゴリズムを変更できる」ということです。 つぎに、区分の名称を得るために既存のクラス SubDivisionName を利用しています。こういったクラスの数が少なければ、どのクラスを利用すればよいか迷わないかもしれませんが、たくさんあった場合には間違ったクラスのインスタンスを生成してしまうこともあるかもしれません。そこで、使用するクラスのインスタンスを生成するメソッド(createDivisionName メソッド)をあらかじめスーパークラス(あるいはサブクラス)の中に記述しておけば、利用者がクラスの選択で迷うことはなくなります。これが、2の「一緒に利用しなければならないクラスを指定する」ということです。 |