Strategyパターン
アルゴリズムの集合を定義し、交換可能にする
Strategy とは英語で「戦略」を意味する言葉です。「アルゴリズム」と考えていいでしょう。Strategy パターンを利用することで、戦略の切り替えや追加が簡単に行えるようになります。

普通にプログラミングしていると、メソッドの中に溶け込んだ形でアルゴリズムを実装してしまうことがよくあります。if 文などで分岐させることでアルゴリズムを変更するような方法です。Strategy パターンでは、戦略の部分を意識して別クラスとして作成するようにしています。戦略部分を別クラスとして作成しておき、戦略を変更したい場合には、利用する戦略クラスを変更するという方法で対応します。Strategy パターンを利用することで、メソッドの中に溶け込んだ形のアルゴリズムより柔軟でメンテナンスしやすい設計となります。
実際には、最近のクラスライブラリは非常に充実しているため、アルゴリズムを実装する機会というのは少ないかもしれません。しかし、組み込み系のプログラミングでは既存のクラスライブラリをそのまま使うわけにはいかず、必要な部分だけ抽出するといったこともあると思います。
そういった場合にStrategyパターンを知っていれば、デスクトップ用には既存のクラスライブラリのアルゴリズムを利用できるようにし、組み込み系用には自作のクラスライブラリのアルゴリズムを利用できるようにする、といったことも可能になります。もちろん、利用するクラスライブラリの切り替えをしたいという単純な場合も適用できます。
Strategy パターンを使えば、プログラムの実行中にクラスを切り替えることもできます。例えば、メモリが少ない環境ではスピードは遅いが省メモリのアルゴリズム、メモリが多い環境ではメモリを食うがスピードは速いアルゴリズムを使うといったことも考えられます。
例題
直方体同士の縦、横、高さをそれぞれ比較するクラス作ります。
共通クラス
|
Strategyパターンを使用しない例 Comparison.java public class Comparison {
public int compare(int type, Hexahedron h1, Hexahedron h2) {
if (type == 0) { // 縦
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
else if (type == 1) { // 横
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
else { // 高さ
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
}
Main.java public class Main {
public static void main(String[] args) {
Hexahedron h1 = new Hexahedron(10, 10, 10);
Hexahedron h2 = new Hexahedron(20, 5, 10);
Comparison comp = new Comparison();
System.out.println(comp.compare(0, h1, h2));
}
}
|
Strategyパターンを使用した例 ICompare.java public interface ICompare {
public int compare(Hexahedron h1, Hexahedron h2);
}
CompareLength.java public class CompareLength implements ICompare {
public int compare(Hexahedron h1, Hexahedron h2) {
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
}
CompareSide.java public class CompareSide implements ICompare {
public int compare(Hexahedron h1, Hexahedron h2) {
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
}
CompareHeight.java public class CompareHeight implements ICompare {
public int compare(Hexahedron h1, Hexahedron h2) {
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
Comparison.java public class Comparison {
private ICompare comp;
public Comparison(ICompare comp) {
this.comp = comp;
}
public int compare(Hexahedron h1, Hexahedron h2) {
return comp.compare(h1, h2);
}
}
Main.java public class Main {
public static void main(String[] args) {
Hexahedron h1 = new Hexahedron(10, 10, 10);
Hexahedron h2 = new Hexahedron(20, 5, 10);
Comparison comp = new Comparison(new CompareLength());
System.out.println(comp.compare(h1, h2));
}
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 comparison.h #include "hexahedron.h"
class Comparison
{
public:
Comparison(void);
virtual ~Comparison(void);
int compare(int, Hexahedron&, Hexahedron&);
}; comparison.cpp #include "comparison.h"
Comparison::Comparison(void) {}
Comparison::~Comparison(void) {}
int Comparison::compare(int type, Hexahedron& h1, Hexahedron& h2) {
if (type == 0) { // 縦
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
else if (type == 1) { // 横
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
else { // 高さ
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
} main.cpp #include <iostream>
using namespace std;
#include "comparison.h"
int main() {
Hexahedron h1(10, 10, 10);
Hexahedron h2(20, 5, 10);
Comparison comp;
cout << comp.compare(0, h1, h2) << endl;
return 0;
}
|
Strategyパターンを使用した例 iCompare.h #include "hexahedron.h"
class ICompare
{
public:
ICompare(void);
virtual ~ICompare(void);
virtual int compare(Hexahedron&, Hexahedron&) = 0;
}; iCompare.cpp #include "iCompare.h"
ICompare::ICompare(void) {}
ICompare::~ICompare(void) {}
comparisonLength.h #include "compimp.h"
#include "hexahedron.h"
class ComparisonLength : public ICompare
{
public:
ComparisonLength(void);
virtual ~ComparisonLength(void);
int compare(Hexahedron& h1, Hexahedron& h2);
}; comparisonLength.cpp #include "comparisonLength.h"
ComparisonLength::ComparisonLength(void) {}
ComparisonLength::~ComparisonLength(void) {}
int ComparisonLength::compare(Hexahedron& h1, Hexahedron& h2) {
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
} comparisonSide.h #include "compimp.h"
#include "hexahedron.h"
class ComparisonSide : public ICompare
{
public:
ComparisonSide(void);
virtual ~ComparisonSide(void);
int compare(Hexahedron& h1, Hexahedron& h2);
}; comparisonSide.cpp #include "comparisonSide.h"
ComparisonSide::ComparisonSide(void) {}
ComparisonSide::~ComparisonSide(void) {}
int ComparisonSide::compare(Hexahedron& h1, Hexahedron& h2) {
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
} comparisonHeight.h #include "compimp.h"
#include "hexahedron.h"
class ComparisonHeight : public ICompare
{
public:
ComparisonHeight(void);
virtual ~ComparisonHeight(void);
int compare(Hexahedron& h1, Hexahedron& h2;
}; comparisonHeight.cpp #include "comparisonHeight.h"
ComparisonHeight::ComparisonHeight(void) {}
ComparisonHeight::~ComparisonHeight(void) {}
int ComparisonHeight::compare(Hexahedron& h1, Hexahedron& h2) {
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
} comparison.h #include "compimp.h"
#include "hexahedron.h"
class Comparison
{
private:
ICompare* comp;
public:
Comparison(void);
Comparison(ICompare* comp);
virtual ~Comparison(void);
int compare(Hexahedron&, Hexahedron&);
}; comparison.cpp #include "comparison.h"
Comparison::Comparison(void) {}
Comparison::Comparison(ICompare* c) : comp(c) {}
Comparison::~Comparison(void) {}
int Comparison::compare(Hexahedron& h1, Hexahedron& h2) {
return comp->compare(h1, h2);
} main.cpp #include <iostream>
using namespace std;
#include "comparison.h"
#include "comparisonLength.h"
int main() {
Hexahedron h1(10, 10, 10);
Hexahedron h2(20, 5, 10);
ComparisonLength c;
Comparison comp(&c);
cout << comp.compare(h1, h2) << endl;
return 0;
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、CompareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.cs class Comparison
{
public int Compare(int type, Hexahedron h1, Hexahedron h2)
{
if (type == 0) // 縦
return h1.length - h2.length;
else if (type == 1) // 横
return h1.side - h2.side;
else // 高さ
return h1.height - h2.height;
}
} Program.cs class Program
{
static void Main(string[] args)
{
Hexahedron h1 = new Hexahedron(10, 10, 10);
Hexahedron h2 = new Hexahedron(20, 5, 10);
Comparison comp = new Comparison();
Console.WriteLine(comp.Compare(0, h1, h2));
}
}
|
Strategyパターンを使用した例 ICompare.cs interface ICompare
{
int Compare(Hexahedron h1, Hexahedron h2);
} CompareLength.cs class CompareLength : ICompare
{
public int Compare(Hexahedron h1, Hexahedron h2)
{
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
} CompareSide.cs class CompareSide : ICompare
{
public int Compare(Hexahedron h1, Hexahedron h2)
{
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
} CompareHeight.cs class CompareHeight : ICompare
{
public int Compare(Hexahedron h1, Hexahedron h2)
{
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
} Comparison.cs class Comparison
{
ICompare comp;
public Comparison(ICompare comp)
{
this.comp = comp;
}
public int Compare(Hexahedron h1, Hexahedron h2)
{
return comp.Compare(h1, h2);
}
} Program.cs class Program
{
static void Main(string[] args)
{
Hexahedron h1 = new Hexahedron(10, 10, 10);
Hexahedron h2 = new Hexahedron(20, 5, 10);
Comparison comp = new Comparison(new CompareLength());
Console.WriteLine(comp.Compare(h1, h2));
}
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、CompareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
既存クラス
|
Strategyパターンを使用しない例 Comparison.vb Public Class Comparison
Public Function Compare(type As Integer, h1 As Hexahedron, h2 As Hexahedron)
If type = 0 Then ' 縦
Return h1.length - h2.length
ElseIf type = 1 Then ' 横
Return h1.side - h2.side
Else ' 高さ
Return h1.height - h2.height
End If
End Function
End Class
Program.vb Module Main
Sub Main()
Dim h1 As Hexahedron = New Hexahedron(10, 10, 10)
Dim h2 As Hexahedron = New Hexahedron(20, 5, 10)
Dim comp As Comparison = New Comparison()
Console.WriteLine(comp.compare(0, h1, h2))
End Sub
End Module
|
Strategyパターンを使用した例 ICompare.vb Public Interface ICompare
Function compare(ByVal h1 As Hexahedron, ByVal h2 As Hexahedron) As Integer
End Interface
CompareLength.vb Public Class CompareLength
Implements ICompare
Public Function compare(ByVal h1 As Hexahedron, ByVal h2 As Hexahedron) _
As Integer Implements ICompare.compare
Return h1.length - h2.length
End Function
End Class
CompareSide.vb Public Class CompareSide
Implements ICompare
Public Function compare(ByVal h1 As Hexahedron, ByVal h2 As Hexahedron) _
As Integer Implements ICompare.compare
Return h1.side - h2.side
End Function
End Class
CompareHeight.vb Public Class CompareHeight
Implements ICompare
Public Function compare(ByVal h1 As Hexahedron, ByVal h2 As Hexahedron) _
As Integer Implements ICompare.compare
Return h1.height - h2.height
End Function
End Class
Comparison.vb Public Class Comparison
Private comp As ICompare
Public Sub New(ByVal comp As ICompare)
Me.comp = comp
End Sub
Public Function compare(ByVal h1 As Hexahedron, ByVal h2 As Hexahedron)
Return comp.compare(h1, h2)
End Function
End Class
Program.vb Module Main
Sub Main()
Dim h1 As Hexahedron = New Hexahedron(10, 10, 10)
Dim h2 As Hexahedron = New Hexahedron(20, 5, 10)
Dim comp As Comparison = New Comparison(New CompareLength())
Console.WriteLine(comp.compare(h1, h2))
End Sub
End Module
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、CompareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.js module.exports = class Comparison {
compare(type, h1, h2) {
if (type == 0) { // 縦
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
else if (type == 1) { // 横
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
else { // 高さ
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
} Main.js const Hexahedron = require("./Hexahedron.js");
const Comparison = require("./Comparison.js");
let h1 = new Hexahedron(10, 10, 10);
let h2 = new Hexahedron(20, 5, 10);
let comp = new Comparison();
process.stdout.write(comp.compare(0, h1, h2));
|
Strategyパターンを使用した例 ICompare.js module.exports = class ICompare {
compare() { console.log("compare メソッドを定義してください。"); }
}
CompareLength.js const ICompare = require("./ICompare.js");
module.exports = class CompareLength extends ICompare {
compare(h1, h2) {
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
}
CompareSide.js const ICompare = require("./ICompare.js");
module.exports = class CompareSide extends ICompare {
compare(h1, h2) {
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
}
CompareHeight.js const ICompare = require("./ICompare.js");
module.exports = class CompareHeight extends ICompare {
compare(h1, h2) {
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
Comparison.js module.exports = class Comparison {
constructor(comp) {
this.comp = comp;
}
compare(h1, h2) {
return comp.compare(h1, h2);
}
}
Main.js const Hexahedron = require("./Hexahedron.js");
const Comparison = require("./Comparison.js");
const CompareLength = require("./CompareLength.js");
let h1 = new Hexahedron(10, 10, 10);
let h2 = new Hexahedron(20, 5, 10);
let comp = new Comparison(new CompareLength());
process.stdout.write(comp.compare(h1, h2) + "\n");
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.pm package Comparison {
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub compare {
my ($this, $type, $h1, $h2) = @_;
if ($type == 0) { # 縦
if ($h1->{length} > $h2->{length}) { return 1; }
else if ($h1->{length} < $h2->{length}) { return -1; }
else { return 0; }
}
elsif ($type == 1) { # 横
if ($h1->{side} > $h2->{side}) { return 1; }
elsif ($h1->{side} < $h2->{side}) { return -1; }
else { return 0; }
}
else { # 高さ
if ($h1->{height} > $h2->{height}) { return 1; }
else if ($h1->{height} < $h2->{height}) { return -1; }
else { return 0; }
}
}
}
1; Main.pl use lib qw(./);
use Hexahedron;
use Comparison;
my $h1 = new Hexahedron(10, 10, 10);
my $h2 = new Hexahedron(20, 5, 10);
my $comp = new Comparison();
print $comp->compare(0, $h1, $h2) . "\n";
|
Strategyパターンを使用した例 ICompare.pm package ICompare {
sub compare { print "compare メソッドを定義してください。"; }
}
1; CompareLength.pm package CompareLength {
use base qw(ICompare);
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub compare {
my ($this, $h1, $h2) = @_;
if ($h1->{length} > $h2->{length}) { return 1; }
else if ($h1->{length} < $h2->{length}) { return -1; }
else { return 0; }
}
}
1; CompareSide.pm package CompareSide {
use base qw(ICompare);
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub compare {
my ($this, $h1, $h2) = @_;
if ($h1->{side} > $h2->{side}) { return 1; }
else if ($h1->{side} < $h2->{side}) { return -1; }
else { return 0; }
}
}
1; CompareHeight.js package CompareHeight {
use base qw(ICompare);
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub compare {
my ($this, $h1, $h2) = @_;
if ($h1->{height} > $h2->{height}) { return 1; }
else if ($h1->{height} < $h2->{height}) { return -1; }
else { return 0; }
}
}
1; Comparison.pm package Comparison {
sub new {
my ($class, $comp) = @_;
my $this = { comp => $comp };
return bless $this, $class;
}
sub compare {
my ($this, $h1, $h2) = @_;
return $this->{comp}->compare($h1, $h2);
}
}
1; Main.pl use lib qw(./);
use Hexahedron;
use Comparison;
use CompareLength;
my $h1 = new Hexahedron(10, 10, 10);
my $h2 = new Hexahedron(20, 5, 10);
my $comp = new Comparison(new CompareLength());
print $comp->compare($h1, $h2) . "\n";
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.rb class Comparison
def compare(type, h1, h2)
if type == 0 then # 縦
if h1.length > h2.length then
return 1
elsif h1.length < h2.length then
return -1
else
return 0
end
elsif type == 1 then # 横
if h1.side > h2.side then
return 1
elsif h1.side < h2.side then
return -1
else
return 0
end
else # 高さ
if h1.height > h2.height then
return 1
elsif h1.height < h2.height then
return -1
else
return 0
end
end
end
end
Main.rb require './Hexahedron'
require './Comparison'
h1 = Hexahedron.new(10, 10, 10)
h2 = Hexahedron.new(20, 5, 10)
comp = Comparison.new()
puts comp.compare(0, h1, h2)
|
Strategyパターンを使用した例 ICompare.rb class ICompare
def compare()
puts "compare メソッドを定義してください。"
end
end
CompareLength.rb require './ICompare'
class CompareLength < ICompare
def compare(h1, h2)
if h1.length > h2.length then
return 1
elsif h1.length < h2.length then
return -1
else
return 0
end
end
end
CompareSide.rb require './ICompare'
class CompareSide < ICompare
def compare(h1, h2) then
if h1.side > h2.side then
return 1
elsif h1.side < h2.side then
return -1
else
return 0
end
end
end
CompareHeight.rb require './ICompare'
class CompareHeight < ICompare
def compare(h1, h2 then
if h1.height > h2.height then
return 1
elsif h1.height < h2.height then
return -1
else
return 0
end
end
end
Comparison.rb class Comparison
def initialize(comp)
@comp = comp
end
def compare(h1, h2)
return @comp.compare(h1, h2)
end
end
Main.rb require './Hexahedron'
require './Comparison'
require './CompareLength'
h1 = Hexahedron.new(10, 10, 10)
h2 = Hexahedron.new(20, 5, 10)
comp = Comparison.new(CompareLength.new())
puts comp.compare(h1, h2)
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.py class Comparison:
def compare(self, type, h1, h2):
if type == 0: # 縦
if h1.length > h2.length:
return 1
elif h1.length < h2.length:
return -1
else:
return 0
elif type == 1: # 横
if h1.side > h2.side:
return 1
elif h1.side < h2.side:
return -1
else:
return 0
else: # 高さ
if h1.height > h2.height:
return 1
elif h1.height < h2.height:
return -1
else:
return 0 Main.py from Hexahedron import Hexahedron
from Comparison import Comparison
h1 = Hexahedron(10, 10, 10)
h2 = Hexahedron(20, 5, 10)
comp = Comparison()
print(comp.compare(0, h1, h2))
|
Strategyパターンを使用した例 ICompare.py from abc import ABCMeta, abstractmethod
class ICompare(metaclass=ABCMeta):
@abstractmethod
def compare(self, h1, h2):
pass
CompareLength.py from ICompare import ICompare
class CompareLength(ICompare):
def compare(self, h1, h2):
if h1.length > h2.length:
return 1
elif h1.length < h2.length:
return -1
else:
return 0
CompareSide.py from ICompare import ICompare
class CompareSide(ICompare):
def compare(self, h1, h2):
if h1.side > h2.side:
return 1
elif h1.side < h2.side:
return -1
else:
return 0
CompareHeight.py from ICompare import ICompare
class CompareHeight(ICompare):
def compare(self, h1, h2):
if h1.height > h2.height:
return 1
elif h1.height < h2.height:
return -1
else:
return 0
Comparison.py class Comparison:
def __init__(self, comp):
self.comp = comp
def compare(self, h1, h2):
return self.comp.compare(h1, h2)
Main.py from Hexahedron import Hexahedron
from Comparison import Comparison
from CompareLength import CompareLength
h1 = Hexahedron(10, 10, 10)
h2 = Hexahedron(20, 5, 10)
comp = Comparison(CompareLength())
print(comp.compare(h1, h2))
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.php <?php
class Comparison {
public function compare($type, $h1, $h2) {
if ($type == 0) { // 縦
if ($h1->length > $h2->length) return 1;
else if ($h1->length < $h2->length) return -1;
else return 0;
}
else if ($type == 1) { // 横
if ($h1->side > $h2->side) return 1;
else if ($h1->side < $h2->side) return -1;
else return 0;
}
else { // 高さ
if ($h1->height > $h2->height) return 1;
else if ($h1->height < $h2->height) return -1;
else return 0;
}
}
}
?>
Main.java <?php
$h1 = new Hexahedron(10, 10, 10);
$h2 = new Hexahedron(20, 5, 10);
$comp = new Comparison();
print $comp->compare(0, $h1, $h2);
?>
|
Strategyパターンを使用した例 ICompare.php <?php
interface ICompare {
public function compare($h1, $h2);
}
CompareLength.php <?php
require_once('ICompare.php');
class CompareLength implements ICompare {
public function compare($h1, $h2) {
if ($h1->length > $h2->length) return 1;
else if ($h1->length < $h2->length) return -1;
else return 0;
}
}
?>
CompareSide.php <?php
require_once('ICompare.php');
class CompareSide implements ICompare {
public function compare($h1, $h2) {
if ($h1->side > $h2->side) return 1;
else if ($h1->side < $h2->side) return -1;
else return 0;
}
} CompareHeight.php <?php
require_once('ICompare.php');
class CompareHeight implements ICompare {
public function compare($h1, $h2) {
if ($h1->height > $h2->height) return 1;
else if ($h1->height < $h2->height) return -1;
else return 0;
}
}
?>
Comparison.php <?php
class Comparison {
public function __construct($comp) {
$this->comp = $comp;
}
public function compare($h1, $h2) {
return $this->comp->compare($h1, $h2);
}
}
?>
Main.php <?php
require_once('Hexahedron.php');
require_once('Comparison.php');
require_once('CompareLength.php');
$h1 = new Hexahedron(10, 10, 10);
$h2 = new Hexahedron(20, 5, 10);
$comp = new Comparison(new CompareLength());
print $comp->compare($h1, $h2));
?>
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.ts import {Hexahedron} from "./Hexahedron";
export
class Comparison {
public int compare(type:number, h1:Hexahedron, h2:Hexahedron):number {
if (type == 0) { // 縦
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
else if (type == 1) { // 横
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
else { // 高さ
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
}
Main.ts import {Hexahedron} from "./Hexahedron";
import {Comparison} from "./Comparison";
let h1:Hexahedron = new Hexahedron(10, 10, 10);
let h2:Hexahedron = new Hexahedron(20, 5, 10);
let comp:Comparison = new Comparison();
process.stdout.write(comp.compare(0, h1, h2) + "\n");
|
Strategyパターンを使用した例 ICompare.ts import {Hexahedron} from "./Hexahedron";
export
interface ICompare {
compare(h1:Hexahedron, h2:Hexahedron);
}
CompareLength.ts import {ICompare} from "./ICompare";
import {Hexahedron} from "./Hexahedron";
export
class CompareLength implements ICompare {
public compare(h1:Hexahedron, h2:Hexahedron):number {
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
}
CompareSide.ts import {ICompare} from "./ICompare";
import {Hexahedron} from "./Hexahedron";
export
class CompareSide implements ICompare {
public compare(h1:Hexahedron, h2:Hexahedron):number {
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
}
CompareHeight.ts import {ICompare} from "./ICompare";
import {Hexahedron} from "./Hexahedron";
export
class CompareHeight implements ICompare {
public compare(h1:Hexahedron, h2:Hexahedron):number {
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
Comparison.ts import {Hexahedron} from "./Hexahedron";
export
class Comparison {
private comp:ICompare;
public Comparison(comp:ICompare) {
this.comp = comp;
}
public compare(h1:Hexahedron, h2:Hexahedron):number {
return this.comp.compare(h1, h2);
}
} Main.ts import {Hexahedron} from "./Hexahedron";
import {Comparison} from "./Comparison";
import {CompareLength} from "./CompareLength";
let h1:Hexahedron = new Hexahedron(10, 10, 10);
let h2:Hexahedron = new Hexahedron(20, 5, 10);
let comp:Comparison = new Comparison(new CompareLength());
process.stdout.write(comp.compare(h1, h2) + "\n");
}
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.swift public class Comparison {
public func compare(_ type:Int, _ h1:Hexahedron, _ h2:Hexahedron) -> Int {
if type == 0 { // 縦
if h1.length > h2.length { return 1 }
else if h1.length < h2.length { return -1 }
else { return 0 }
}
else if type == 1 { // 横
if h1.side > h2.side { return 1 }
else if h1.side < h2.side { return -1 }
else { return 0 }
}
else { // 高さ
if h1.height > h2.height { return 1 }
else if h1.height < h2.height { return -1 }
else { return 0 }
}
}
}
Main.swift let h1:Hexahedron = Hexahedron(10, 10, 10)
let h2:Hexahedron = Hexahedron(20, 5, 10)
let comp:Comparison = Comparison()
print(comp.compare(0, h1, h2))
|
Strategyパターンを使用した例 ICompare.swift public protocol ICompare {
func compare(_ h1:Hexahedron, _ h2:Hexahedron) -> Int
}
CompareLength.swift public class CompareLength : ICompare {
public func compare(_ h1:Hexahedron, _ h2:Hexahedron) -> Int {
if h1.length > h2.length { return 1 }
else if h1.length < h2.length { return -1 }
else { return 0 }
}
}
CompareSide.swift public class CompareSide : ICompare {
public func compare(_ h1:Hexahedron, _ h2:Hexahedron) -> Int {
if h1.side > h2.side { return 1 }
else if h1.side < h2.side { return -1 }
else { return 0 }
}
}
CompareHeight.swift public class CompareHeight : ICompare {
public func compare(_ h1:Hexahedron, _ h2:Hexahedron) -> Int {
if h1.height > h2.height { return 1 }
else if h1.height < h2.height { return -1 }
else { return 0 }
}
}
Comparison.swift public class Comparison {
private var comp:ICompare
public init(_ comp:ICompare) {
self.comp = comp
}
public func compare(_ h1:Hexahedron, _ h2:Hexahedron) -> Int {
return comp.compare(h1, h2)
}
} Main.swift let h1:Hexahedron = Hexahedron(10, 10, 10)
let h2:Hexahedron = Hexahedron(20, 5, 10)
let comp:Comparison = Comparison(CompareLength())
print(comp.compare(h1, h2))
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.kt class Comparison {
fun compare(type: Int, h1: Hexahedron, h2: Hexahedron): Int {
return if (type == 0) { // 縦
if (h1.length > h2.length) 1
else if (h1.length < h2.length) -1
else 0
}
else if (type == 1) { // 横
if (h1.side > h2.side) 1
else if (h1.side < h2.side) -1
else 0
}
else { // 高さ
if (h1.height > h2.height) 1
else if (h1.height < h2.height) -1
else 0
}
}
}
Main.kt fun main() {
val h1 = Hexahedron(10, 10, 10)
val h2 = Hexahedron(20, 5, 10)
val comp = Comparison()
println(comp.compare(0, h1, h2))
}
|
Strategyパターンを使用した例 ICompare.kt interface ICompare {
fun compare(h1:Hexahedron, h2:Hexahedron) : Int
}
CompareLength.kt class CompareLength : ICompare {
override fun compare(h1:Hexahedron, h2:Hexahedron): Int {
return if (h1.length > h2.length) 1
else if (h1.length < h2.length) -1
else return 0
}
}
CompareSide.kt class CompareSide : ICompare {
fun compare(h1:Hexahedron, h2:Hexahedron): Int {
return if (h1.side > h2.side) 1
else if (h1.side < h2.side) -1
else 0
}
}
CompareHeight.kt class CompareHeight : ICompare {
fun compare(h1:Hexahedron, h2:Hexahedron): Int {
if (h1.height > h2.height) 1
else if (h1.height < h2.height) -1
else 0
}
}
Comparison.kt class Comparison(private val comp: ICompare) {
fun compare(h1: Hexahedron, h2: Hexahedron): Int {
return comp.compare(h1, h2)
}
}
Main.kt fun main() {
val h1 = Hexahedron(10, 10, 10)
val h2 = Hexahedron(20, 5, 10)
val comp = Comparison(CompareLength())
println(comp.compare(h1, h2))
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.scala class Comparison {
def compare(`type`: Int, h1: Hexahedron, h2: Hexahedron): Int =
if (`type` == 0) { // 縦
if (h1.length > h2.length) 1
else if (h1.length < h2.length) -1
else 0
}
else if (`type` == 1) { // 横
if (h1.side > h2.side) 1
else if (h1.side < h2.side) -1
else 0
}
else { // 高さ
if (h1.height > h2.height) 1
else if (h1.height < h2.height) -1
else 0
}
}
Main.scala object Main {
def main(args: Array[String]) {
val h1 = new Hexahedron(10, 10, 10)
val h2 = new Hexahedron(20, 5, 10)
val comp = new Comparison()
System.out.println(comp.compare(0, h1, h2))
}
}
|
Strategyパターンを使用した例 ICompare.scala trait ICompare {
def compare(h1:Hexahedron, h2:Hexahedron) : Int
}
CompareLength.scala class CompareLength extends ICompare {
def compare(h1:Hexahedron, h2:Hexahedron): Int =
if (h1.length > h2.length) 1
else if (h1.length < h2.length) -1
else 0
}
}
CompareSide.scala class CompareSide extends ICompare {
def compare(h1:Hexahedron, h2:Hexahedron): Int =
if (h1.side > h2.side) 1
else if (h1.side < h2.side) -1
else 0
}
}
CompareHeight.scala class CompareHeight extends ICompare {
def compare(h1:Hexahedron, h2:Hexahedron): Int =
if (h1.height > h2.height) 1
else if (h1.height < h2.height) -1
else 0
}
}
Comparison.scala class Comparison(val comp: ICompare) {
def compare(h1: Hexahedron, h2: Hexahedron): Int = comp.compare(h1, h2)
}
Main.scala object Main {
def main(args: Array[String]) {
val h1 = new Hexahedron(10, 10, 10)
val h2 = new Hexahedron(20, 5, 10)
val comp = new Comparison(new CompareLength())
System.out.println(comp.compare(h1, h2))
}
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.groovy class Comparison {
int compare(int type, Hexahedron h1, Hexahedron h2) {
if (type == 0) { // 縦
if (h1.length > h2.length) return 1
else if (h1.length < h2.length) return -1
else return 0
}
else if (type == 1) { // 横
if (h1.side > h2.side) return 1
else if (h1.side < h2.side) return -1
else return 0
}
else { // 高さ
if (h1.height > h2.height) return 1
else if (h1.height < h2.height) return -1
else return 0
}
}
} Main.groovy class Main {
static void main(String[] args) {
Hexahedron h1 = new Hexahedron(10, 10, 10)
Hexahedron h2 = new Hexahedron(20, 5, 10)
Comparison comp = new Comparison()
System.out.println(comp.compare(0, h1, h2))
}
}
|
Strategyパターンを使用した例 ICompare.groovy interface ICompare {
int compare(Hexahedron h1, Hexahedron h2)
}
CompareLength.groovy class CompareLength implements ICompare {
int compare(Hexahedron h1, Hexahedron h2) {
if (h1.length > h2.length) return 1
else if (h1.length < h2.length) return -1
else return 0
}
}
CompareSide.groovy class CompareSide implements ICompare {
int compare(Hexahedron h1, Hexahedron h2) {
if (h1.side > h2.side) return 1
else if (h1.side < h2.side) return -1
else return 0
}
}
CompareHeight.groovy class CompareHeight implements ICompare {
int compare(Hexahedron h1, Hexahedron h2) {
if (h1.height > h2.height) return 1
else if (h1.height < h2.height) return -1
else return 0
}
} Comparison.groovy class Comparison {
private ICompare comp
Comparison(ICompare comp) {
this.comp = comp
}
int compare(Hexahedron h1, Hexahedron h2) {
return comp.compare(h1, h2)
}
}
Main.groovy class Main {
static void main(String[] args) {
Hexahedron h1 = new Hexahedron(10, 10, 10)
Hexahedron h2 = new Hexahedron(20, 5, 10)
Comparison comp = new Comparison(new CompareLength())
System.out.println(comp.compare(h1, h2))
}
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.go type Comparison struct {}
func (self * Comparison) Compare(typ int, h1 Hexahedron, h2 Hexahedron) int {
if typ == 0 { // 縦
if h1.Length > h2.Length {
return 1
} else if h1.Length < h2.Length {
return -1
} else {
return 0
}
} else if typ == 1 { // 横
if h1.Side > h2.Side {
return 1
} else if h1.Side < h2.Side {
return -1
} else {
return 0
}
} else { // 高さ
if h1.Height > h2.Height {
return 1
} else if h1.Height < h2.Height {
return -1
} else {
return 0
}
}
}
func NewComparison() *Comparison {
return new(Comparison)
}
Main.go import "fmt"
func main() {
var h1 = NewHexahedron(10, 10, 10)
var h2 = NewHexahedron(20, 5, 10)
var comp = NewComparison()
fmt.Println(comp.Compare(0, h1, h2))
}
|
Strategyパターンを使用した例 ICompare.go type ICompare interface {
Compare(*Hexahedron, *Hexahedron) int
}
CompareLength.go type CompareLength struct {
ICompare
}
func (self *CompareLength) Compare(h1 *Hexahedron, h2 *Hexahedron) int {
if h1.Length > h2.Length {
return 1
} else if h1.Length < h2.Length {
return -1
} else {
return 0
}
}
func NewCompareLength() ICompare {
return &CompareLength{}
}
CompareSide.go type CompareSide struct {
ICompare
}
func (self *CompareSide) Compare(h1 *Hexahedron, h2 *Hexahedron) int {
if h1.Side > h2.Side {
return 1
} else if h1.Side < h2.Side {
return -1
} else {
return 0
}
}
func NewCompareSide() ICompare {
return &CompareSide{}
}
CompareHeight.go type CompareHeight struct {
ICompare
}
func (self *CompareHeight) Compare(h1 *Hexahedron, h2 *Hexahedron) int {
if h1.Height > h2.Height {
return 1
} else if h1.Height < h2.Height {
return -1
} else {
return 0
}
}
func NewCompareHeight() ICompare {
return &CompareHeight{}
}
Comparison.go type Comparison struct {
comp ICompare
}
func (self *Comparison) Compare(h1 *Hexahedron, h2 *Hexahedron) int {
return self.comp.Compare(h1, h2)
}
func NewComparison(comp ICompare) *Comparison {
return &Comparison{
comp: comp,
}
}
Main.go import "fmt"
func main() {
var h1 = NewHexahedron(10, 10, 10)
var h2 = NewHexahedron(20, 5, 10)
var comp = NewComparison(NewCompareLength())
fmt.Println(comp.Compare(h1, h2))
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 comparison.d import hexahedron;
public class Comparison {
public int compare(in int type, Hexahedron h1, Hexahedron h2) {
if (type == 0) { // 縦
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
else if (type == 1) { // 横
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
else { // 高さ
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
}
main.d import std.stdio;
import hexahedron;
import comparison;
public int main() {
Hexahedron h1 = new Hexahedron(10, 10, 10);
Hexahedron h2 = new Hexahedron(20, 5, 10);
Comparison comp = new Comparison();
writeln(comp.compare(0, h1, h2));
return 0;
}
|
Strategyパターンを使用した例 icompare.d import hexahedron;
public interface ICompare {
public int compare(Hexahedron h1, Hexahedron h2);
}
comparelength.d import icompare;
import hexahedron;
public class CompareLength : ICompare {
public int compare(Hexahedron h1, Hexahedron h2) {
if (h1.length > h2.length) return 1;
else if (h1.length < h2.length) return -1;
else return 0;
}
}
compareside.d import icompare;
import hexahedron;
public class CompareSide : ICompare {
public int compare(Hexahedron h1, Hexahedron h2) {
if (h1.side > h2.side) return 1;
else if (h1.side < h2.side) return -1;
else return 0;
}
}
compareheight.d import icompare;
import hexahedron;
public class CompareHeight : ICompare {
public int compare(Hexahedron h1, Hexahedron h2) {
if (h1.height > h2.height) return 1;
else if (h1.height < h2.height) return -1;
else return 0;
}
}
comparison.d import icompare;
import hexahedron;
public class Comparison {
private ICompare comp;
public this(ICompare comp) {
this.comp = comp;
}
public int compare(Hexahedron h1, Hexahedron h2) {
return comp.compare(h1, h2);
}
}
main.d import std.stdio;
import hexahedron;
import comparison;
import comparelength;
public int main() {
Hexahedron h1 = new Hexahedron(10, 10, 10);
Hexahedron h2 = new Hexahedron(20, 5, 10);
Comparison comp = new Comparison(new CompareLength());
writeln(comp.compare(h1, h2));
return 0;
}
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |
共通クラス
|
Strategyパターンを使用しない例 Comparison.pas unit UnitComparison;
interface
uses
UnitHexahedron;
type
Comparison = class
public
function compare(typ:integer; h1:Hexahedron; h2:Hexahedron):integer;
end;
implementation
function Comparison.compare(typ:integer; h1:Hexahedron; h2:Hexahedron):integer;
begin
if typ = 0 then begin // 縦
if h1.length > h2.length then begin
Result := 1;
end
else if h1.length < h2.length then begin
Result := -1;
end
else begin
Result := 0;
end
end
else if typ = 1 then begin // 横
if h1.side > h2.side then begin
Result := 1;
end
else if h1.side < h2.side then begin
Result := -1;
end
else begin
Result := 0;
end
end
else begin // 高さ
if h1.height > h2.height then begin
Result := 1;
end
else if h1.height < h2.height then begin
Result := -1;
end
else begin
Result := 0;
end
end;
end;
end.
Main.pas program Main;
uses
System.SysUtils,
UnitHexahedron,
UnitComparison;
var h1:Hexahedron;
var h2:Hexahedron;
var comp:Comparison;
begin
h1 := Hexahedron.Create(10, 10, 10);
h2 := Hexahedron.Create(20, 5, 10);
comp := Comparison.Create();
Writeln(comp.compare(0, h1, h2));
h1.Free;
h2.Free;
comp.Free;
end.
|
Strategyパターンを使用した例 ICompare.pas unit UnitICompare;
interface
uses
UnitHexahedron;
type
ICompare = interface
function compare(h1:Hexahedron; h2:Hexahedron):integer;
end;
implementation
end.
CompareLength.pas unit UnitCompareLength;
interface
uses
UnitICompare,
UnitHexahedron;
type
CompareLength = class(TInterfacedObject, ICompare)
function compare(h1:Hexahedron; h2:Hexahedron):integer;
end;
implementation
function CompareLength.compare(h1:Hexahedron; h2:Hexahedron):integer;
begin
if h1.length > h2.length then begin
Result := 1;
end
else if h1.length < h2.length then begin
Result := -1;
end
else begin
Result := 0;
end
end;
end.
CompareSide.pas unit UnitCompareLength;
interface
uses
UnitICompare,
UnitHexahedron;
type
CompareSide = class(TInterfacedObject, ICompare)
function compare(h1:Hexahedron; h2:Hexahedron):integer;
end;
implementation
function CompareSide.compare(h1:Hexahedron; h2:Hexahedron):integer;
begin
if h1.side > h2.side then begin
Result := 1;
end
else if h1.side < h2.side then begin
Result := -1;
end
else begin
Result := 0;
end
end;
end.
CompareHeight.pas unit UnitCompareLength;
interface
uses
UnitICompare,
UnitHexahedron;
type
CompareHeight = class(TInterfacedObject, ICompare)
function compare(h1:Hexahedron; h2:Hexahedron):integer;
end;
implementation
function CompareHeight.compare(h1:Hexahedron; h2:Hexahedron):integer;
begin
if h1.height > h2.height then begin
Result := 1;
end
else if h1.height < h2.height then begin
Result := -1;
end
else begin
Result := 0;
end
end;
end.
Comparison.pas unit UnitComparison;
interface
uses
UnitICompare,
UnitHexahedron;
type
Comparison = class
public
var comp:ICompare;
public
constructor Create(comp:ICompare);
function compare(h1:Hexahedron; h2:Hexahedron):integer;
end;
implementation
constructor Comparison.Create(comp:ICompare);
begin
self.comp := comp;
end;
function Comparison.compare(h1:Hexahedron; h2:Hexahedron):integer;
begin
Result := comp.compare(h1, h2);
end;
end.
Main.dpr program StrategyGof;
uses
System.SysUtils,
UnitHexahedron,
UnitComparison,
UnitCompareLength;
var h1:Hexahedron;
var h2:Hexahedron;
var comp:Comparison;
begin
h1 := Hexahedron.Create(10, 10, 10);
h2 := Hexahedron.Create(20, 5, 10);
comp := Comparison.Create(CompareLength.Create());
Writeln(comp.compare(h1, h2));
h1.Free;
h2.Free;
comp.Free;
end.
|
|
どの部分を比較するかを引数として与え、例えば、0ならば縦、1ならば横、2ならば高さというように決めます。そして、Comparison クラスでは、if 文によって処理を分岐し、指定された部分の比較します。 この例では、3通りの分岐しかありませんが、もっとあったらどうでしょう。とても煩雑なコードとなってしまいます。このように、メソッドの中に溶け込んだ形で、if 文の分岐を利用してアルゴリズムを変更するようにすると、とても煩雑で、メンテナンス性に乏しいソースコードとなってしまいます。 |
まずは、比較アルゴリズム部分をクラスとして分離します。 このとき、Strategy パターンでは分離したアルゴリズム部分が共通のインタフェースを持つようにすることが求められます。すなわち、アルゴリズムとして分離された複数のクラスが共通のインタフェースを持つ必要があります。ここでは、縦、横、高さを比較するクラスのために、ICompare インタフェースを定義しています。 そして、共通の ICompare インタフェースを持った、縦を比較するための ComparisonLength クラス、横を比較するための ComparisonSize クラス、高さを比較するための ComparisonHeight クラスを作成します。 そこで例えば、縦を比較しようとしたら、compareLength インスタンスを引数に Comparison クラスのインスタンスを生成します。そして、そのインスタンスの compare メソッドを呼び出します。そうすると、compare メソッドは、先に引き渡されたインスタンスである ComparisonLength インスタンスの compare メソッドを呼び出します。こうして、縦が比較されるわけです。 さらに別の比較をするといった、アルゴリズムの追加をする際には、同様に ICompare インタフェースを実装するクラスを追加してやれば済みます。このように、アルゴリズムの部分を別クラスとして作成することで、比較アルゴリズムの追加が簡単になり、メンテナンスの見通しも格段に良くなります。 |