Interpreterパターン
何らかの文法規則で解析された結果を利用する
Interpreter とは、英語で「解釈者・説明者」を意味する単語です。 何らかのフォーマットで書かれたファイルの中身を、解析した結果にそって何らかの処理を行いたい場合があります。 Interpreter パターンとは、このような「解析した結果」得られた手順に則った処理を実現するために最適なパターンです。分かりにくいですが、解析する方法ではなく、解析した結果を利用するパターンです。
そのフォーマットとは、htmlやxml、プロパティファイルのような静的なものもあれば、ソースファイルのように処理手順を記述したものもあります。SQL、シェル、バッチ、マクロ、XSLT等もあります。通常、構文解析という操作で、文法規則にのっとって解析が行なわれ、解析結果はツリー構造のオブジェクトとして保存されます。全体は部分から構成され、部分はさらに小さな部分から構成されます。
全体に対して何らかのメソッドを適用すると、部分に対しても順次再帰的に同じメソッドを呼び出していきます。基本的に、Interpreter はComposite と同じものです。
ただ通常、Composite や Interpreter を適用するパターンは多くありません。再帰的に処理するのが便利なのは、無限に階層が深くなる可能性がある場合で、一覧表示や計算や処理を行う場合です。容器の中に容器を入れられるようにすれば、再帰構造ができあがりますが、設定ファイルなどで用いる場合はかえって混乱を招きます。無限に階層が深くなっても、利用するアプリケーション側で対応する必要が出てくるので、有限の構造にした方がいいこともあります。
例題
四則演算をします。演算の手順はすでに得られています。
1 + 4 * 2
(1 + 4) * 2
10.0
|
Interpreterパターンを使用しない例 Calculator.java public class Calculator {
private double result = 0.0;
public double calculate(Stack<String> operand) {
if (operand.empty())
return result;
String operator = (String)operand.pop();
String operand2 = (String)operand.pop();
double op2;
if (operand2.equals("+") || operand2.equals("*")) {
operand.push(operand2);
op2 = calculate(operand);
}
else {
op2 = Double.parseDouble(operand2);
}
String operand1 = (String)operand.pop();
double op1;
if (operand1.equals("+") || operand1.equals("*")) {
operand.push(operand1);
op1 = calculate(operand);
}
else {
op1 = Double.parseDouble(operand1);
}
if (operator.equals("+")) {
result = op1 + op2;
}
else if (operator.equals("*")) {
result = op1 * op2;
}
return result;
}
}
Main.java public class Main {
public static void main(String[] args) {
Stack<String> operand = new Stack<String>();
// 1 + 4 * 2
operand.push("1");
operand.push("4");
operand.push("2");
operand.push("*");
operand.push("+");
Calculator cal = new Calculator();
System.out.println(cal.calculate(operand));
// (1 + 4) * 2
operand.clear();
operand.push("1");
operand.push("4");
operand.push("+");
operand.push("2");
operand.push("*");
System.out.println(cal.calculate(operand));
}
}
|
Interpreterパターンを使用した例 IOperand.java public interface IOperand {
double getOperand();
}
Ingredient.java public class Ingredient implements IOperand {
private double operand = 0;
public Ingredient(double operand) {
this.operand = operand;
}
public double getOperand() {
return this.operand;
}
}
Expression.java public class Expression implements IOperand {
private IOperator operator = null;
public Expression(IOperator operator) {
this.operator = operator;
}
public double getOperand() {
return operator.execute().getOperand();
}
}
IOperator.java public interface IOperator {
public IOperand execute();
}
OperationAdd.java public class OperationAdd implements IOperator {
private IOperand operand1 = null;
private IOperand operand2 = null;
public OperationAdd(IOperand operand1, IOperand operand2) {
this.operand1 = operand1;
this.operand2 = operand2;
}
public IOperand execute() {
return new Ingredient(operand1.getOperand() + operand2.getOperand());
}
}
OperationMultiply.java public class OperationMultiply implements IOperator {
private IOperand operand1 = null;
private IOperand operand2 = null;
public OperationMultiply(IOperand operand1, IOperand operand2) {
this.operand1 = operand1;
this.operand2 = operand2;
}
public IOperand execute() {
return new Ingredient(operand1.getOperand() * operand2.getOperand());
}
}
Main.java public class Main {
public static void main(String[] args) {
Ingredient in1 = new Ingredient(1);
Ingredient in2 = new Ingredient(4);
Ingredient in3 = new Ingredient(2);
// 1 + 4 * 2
Expression ex1 = new Expression(new OperationMultiply(in2, in3));
Expression ex2 = new Expression(new OperationAdd(in1, ex1));
System.out.println(ex2.getOperand());
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, in2));
ex2 = new Expression(new OperationMultiply(ex1, in3));
System.out.println(ex2.getOperand());
}
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 calculator.h #include <stack>
#include <string>
class Calculator
{
private:
double result;
public:
Calculator(void);
virtual ~Calculator(void);
double calculate(stack<string>&);
}; calculator.cpp #include <sstream>
using namespace std;
#include "calculator.h"
Calculator::Calculator(void) : result(0.0) {}
Calculator::~Calculator(void) {}
double Calculator::calculate(stack<string>& operand) {
if (operand.empty()) return result;
string op = (string)operand.top(); // 演算子
operand.pop();
string operand2 = (string)operand.top();
operand.pop();
double opd2;
if (operand2 == "+" || operand2 == "*") {
operand2.push(operand2);
opd2 = calculate(operand);
}
else {
istringstream is;
is.str(operand2);
is >> opd2;
}
string operand1 = (string)operand.top();
operand.pop();
double opd1;
if (operand1 == "+" || operand1 == "*") {
operand.push(operand1);
opd1 = calculate(operand);
}
else {
istringstream is;
is.str(operand1);
is >> opd1;
}
if (op == "+") {
result = opd1 + opd2;
}
else if (op == "*") {
result = opd1 * opd2;
}
return result;
}
main.cpp #include <iostream>
using namespace std;
#include "calculator.h"
int main() {
stack<string> operand;
// 1 + 4 * 2
operand.push("1");
operand.push("4");
operand.push("2");
operand.push("*");
operand.push("+");
Calculator cal;
cout << cal.calculate(operand) << endl;
// (1 + 4) * 2
operand.push("1");
operand.push("4");
operand.push("+");
operand.push("2");
operand.push("*");
cout << cal.calculate(operand) << endl;
return 0;
}
|
Interpreterパターンを使用した例 ioperand.h class IOperand
{
public:
IOperand(void);
virtual ~IOperand(void);
virtual double getOperand(void) = 0;
}; ioperand.cpp #include "ioperand.h"
IOperand::IOperand(void) {}
IOperand::~IOperand(void) {} ingredient.h #include "ioperand.h"
class Ingredient : public IOperand
{
private:
double value;
public:
Ingredient(void);
Ingredient(double);
virtual ~Ingredient(void);
double getOperand(void);
}; ingredient.cpp #include "ingredient.h"
Ingredient::Ingredient(void) {}
Ingredient::Ingredient(double val) : value(val) {}
Ingredient::~Ingredient(void) {}
double Ingredient::getOperand(void) {
return value;
}
expression.h #include "ioperand.h"
#include "iioperator.h"
class Expression : public IOperand
{
private:
IOperator* op;
public:
Expression(void);
Expression(IOperator*);
virtual ~Expression(void);
double getOperand(void);
}; expression.cpp #include "expression.h"
Expression::Expression(void) {}
Expression::Expression(IOperator* op) : op(op) {}
Expression::~Expression(void) {}
double Expression::getOperand(void) {
return op->execute()->getOperand();
}
ioperator.h #include "ioperand.h"
class IOperator
{
protected:
IOperand* opd;
public:
IOperator(void);
virtual ~IOperator(void);
virtual IOperand* execute(void) = 0;
IOperator& operator=(const IOperator&);
}; ioperator.cpp #include "ioperator.h"
IOperator::IOperator(void) : opd(0) {}
IOperator::~IOperator(void) {}
IOperator& IOperator::operator=(const IOperator& op) {
if (opd != 0 && this != &op) {
delete opd;
opd = 0;
}
return *this;
}
operationAdd.h #include "ioperator.h"
#include "ioperand.h"
class OperationAdd : public IOperator
{
private:
IOperand* operand1;
IOperand* operand2;
public:
OperationAdd(void);
OperationAdd(IOperand*, IOperand*);
~OperationAdd(void);
IOperand* execute(void);
}; operationAdd.cpp #include "OperationAdd.h"
#include "ingredient.h"
OperationAdd::OperationAdd(void) {}
OperationAdd::OperationAdd(IOperand* ope1, IOperand* ope2)
: operand1(ope1), operand2(ope2) {}
OperationAdd::~OperationAdd(void) {
if (opd != 0) delete opd;
}
IOperand* OperationAdd::execute(void) {
opd = new Ingredient(operand1->getOperand() + operand2->getOperand());
return opd;
}
operationMultiply.h #include "ioperator.h"
#include "ioperand.h"
class OperationMultiply : public IOperator
{
private:
IOperand* operand1;
IOperand* operand2;
public:
OperationMultiply(void);
OperationMultiply(IOperand*, IOperand*);
virtual ~OperationMultiply(void);
IOperand* execute(void);
}; operationMultiply.cpp #include "operationMultiply.h"
#include "ingredient.h"
OperationMultiply::OperationMultiply(void) {}
OperationMultiply::OperationMultiply(IOperand* ope1, IOperand* ope2)
: operand1(ope1), operand2(ope2) {}
OperationMultiply::~OperationMultiply(void) {
if (opd != 0) delete opd;
}
IOperand* OperationMultiply::execute(void) {
opd = new Ingredient(operand1->getOperand() * operand2->getOperand());
return opd;
}
main.cpp #include <iostream>
using namespace std;
#include "ingredient.h"
#include "expression.h"
#include "operationAdd.h"
#include "operationMultiply.h"
int main() {
Ingredient in1(1);
Ingredient in2(4);
Ingredient in3(2);
// 1 + 4 * 2
OperationMultiply m(&in2, &in3); // 4 * 2
Expression ex1(&m);
OperationAdd a(&in1, &ex1); // 1 + (4 * 2)
Expression ex2(&a);
cout << ex2.getOperand() << endl;
// (1 + 4) * 2
a = OperationAdd(&in1, &in2); // 1 + 4
ex1 = Expression(&a);
m = OperationMultiply(&ex1, &in3); // (1 + 4) * 2
ex2 = Expression(&m);
cout << ex2.getOperand() << endl;
return 0;
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + /\ 1 * /\ 4 2 というようにオブジェクトを関連付けています。 まず、4*2 を ex1 という Expression インスタンスに作成します。IOperator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。IOperator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の IOperator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.cs class Calculator
{
private double result = 0.0;
public double Calculate(Stack<string> operand)
{
if (operand.Count == 0)
{
return result;
}
string @operator = operand.Pop();
string operand2 = operand.Pop();
double op2;
if (operand2 == "+" || operand2 == "*")
{
operand.Push(operand2);
op2 = Calculate(operand);
}
else
{
op2 = Double.Parse(operand2);
}
string operand1 = operand.Pop();
double op1;
if (operand1 == "+" || operand1 == "*")
{
operand.Push(operand1);
op1 = Calculate(operand);
}
else
{
op1 = Double.Parse(operand1);
}
if (@operator == "+")
result = op1 + op2;
else if (@operator == "*")
result = op1 * op2;
return result;
}
}
Program.cs class Program
{
static void Main(string[] args)
{
Stack<string> operand = new Stack<string>();
// 1 + 4 * 2
operand.Push("1");
operand.Push("4");
operand.Push("2");
operand.Push("*");
operand.Push("+");
Calculator cal = new Calculator();
Console.WriteLine(cal.Calculate(operand));
// (1 + 4) * 2
operand.Push("1");
operand.Push("4");
operand.Push("+");
operand.Push("2");
operand.Push("*");
Console.WriteLine(cal.Calculate(operand));
}
}
|
Interpreterパターンを使用した例 IOperand.cs interface IOperand
{
double GetOperand();
}
Ingredient.cs class Ingredient : IOperand
{
private double operand = 0;
public Ingredient(double operand)
{
this.operand = operand;
}
public double GetOperand()
{
return operand;
}
}
Expression.cs class Expression : IOperand
{
private IOperator @operator = null;
public Expression(IOperator @operator)
{
this.@operator = @operator;
}
public double GetOperand()
{
return @operator.Execute().GetOperand();
}
} IOperator.cs interface IOperator
{
IOperand Execute();
}
OperationAdd.cs class OperationAdd : IOperator
{
private IOperand operand1 = null;
private IOperand operand2 = null;
public OperationAdd(IOperand operand1, IOperand operand2)
{
this.operand1 = operand1;
this.operand2 = operand2;
}
public IOperand Execute()
{
return new Ingredient(operand1.GetOperand() + operand2.GetOperand());
}
}
OperationMultiply.cs class OperationMultiply : IOperator
{
private IOperand operand1 = null;
private IOperand operand2 = null;
public OperationMultiply(IOperand operand1, IOperand operand2)
{
this.operand1 = operand1;
this.operand2 = operand2;
}
public IOperand Execute()
{
return new Ingredient(operand1.GetOperand() * operand2.GetOperand());
}
}
Program.cs class Program
{
static void Main(string[] args)
{
Ingredient in1 = new Ingredient(1);
Ingredient in2 = new Ingredient(4);
Ingredient in3 = new Ingredient(2);
// 1 + 4 * 2
Expression ex1 = new Expression(new OperationMultiply(in2, in3));
Expression ex2 = new Expression(new OperationAdd(in1, ex1));
Console.WriteLine(ex2.GetOperand());
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, ex2));
ex2 = new Expression(new OperationMultiply(ex1, in3));
Console.WriteLine(ex2.GetOperand());
}
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、Calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の Excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(GetOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(Execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの GetOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の Excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.vb Public Class Calculator
Private result As Double = 0.0
Public Function Calculate(ByVal operand As Stack) As Double
If operand.Count = 0 Then Return result
Dim [operator] As String = operand.Pop()
Dim operand2 As String = operand.Pop()
Dim op2 As Double
If operand2 = "+" OrElse operand2 = "*" Then
operand.Push(operand2)
op2 = Calculate(operand)
Else
op2 = operand2
End If
Dim operand1 As String = operand.Pop()
Dim op1 As Double
If operand1 = "+" OrElse operand1 = "*" Then
operand.Push(operand1)
op1 = Calculate(operand)
Else
op1 = operand1
End If
If [operator] = "+" Then
result = op1 + op2
ElseIf [operator] = "*" Then
result = op1 * op2
End If
Return result
End Function
End Class
Program.vb Module Main
Sub Main()
Dim operand As Stack = New Stack()
' 1 + 4 * 2
operand.Push("1")
operand.Push("4")
operand.Push("2")
operand.Push("*")
operand.Push("+")
Dim cal As Calculator = New Calculator()
Console.WriteLine(cal.Calculate(operand))
' (1 + 4) * 2
operand.Push("1")
operand.Push("4")
operand.Push("+")
operand.Push("2")
operand.Push("*")
Console.WriteLine(cal.Calculate(operand))
End Sub
End Module
|
Interpreterパターンを使用した例 IOperand.vb Public Interface IOperand
Function GetOperand() As Double
End Interface
Ingredient.vb Public Class Ingredient
Implements IOperand
Private operand As Double = 0
Public Sub New(ByVal operand As Double)
Me.operand = operand
End Sub
Public Function GetOperand() As Double Implements IOperand.GetOperand
Return operand
End Function
End Class
Expression.vb Public Class Expression
Implements IOperand
Private [operator] As IOperator = Nothing
Public Sub New(ByVal [operator] As IOperator)
Me.[operator] = [operator]
End Sub
Public Function GetOperand() As Double Implements IOperand.GetOperand
Return [operator].Execute().GetOperand()
End Function
End Class
Operator.vb Public Interface IOperator
Function Execute() As IOperand
End Interface
OperationAdd.vb Public Class OperationAdd
Implements IOperator
Private operand1 As IOperand = Nothing
Private operand2 As IOperand = Nothing
Public Sub New(ByVal operand1 As IOperand, ByVal operand2 As IOperand)
Me.operand1 = operand1
Me.operand2 = operand2
End Sub
Public Function Execute() As IOperand Implements IOperator.Execute
Return New Ingredient(operand1.GetOperand() + operand2.GetOperand())
End Function
End Class
OperationMultiply.vb Public Class OperationMultiply
Implements IOperator
Private operand1 As IOperand = Nothing
Private operand2 As IOperand = Nothing
Public Sub New(ByVal operand1 As IOperand, ByVal operand2 As IOperand)
Me.operand1 = operand1
Me.operand2 = operand2
End Sub
Public Function Execute() As IOperand Implements IOperator.Execute
Return New Ingredient(operand1.GetOperand() * operand2.GetOperand())
End Function
End Class
Program.vb Module Main
Sub Main()
Dim in1 As Ingredient = New Ingredient(1)
Dim in2 As Ingredient = New Ingredient(4)
Dim in3 As Ingredient = New Ingredient(2)
' 1 + 4 * 2
Dim ex1 As Expression = New Expression(New OperationMultiply(in2, in3))
Dim ex2 As Expression = New Expression(New OperationAdd(in1, ex1))
Console.WriteLine(ex2.GetOperand())
' (1 + 4) * 2
ex1 = New Expression(New OperationAdd(in1, in2))
ex2 = New Expression(New OperationMultiply(ex1, in3))
Console.WriteLine(ex2.GetOperand())
End Sub
End Module
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、Calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の Excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(GetOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(Execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの GetOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の Excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.js module.exports = class Calculator {
constructor() {
this.result = 0;
}
calculate(operand) {
if (operand.length == 0)
return result;
let operator = operand.pop();
let operand2 = operand.pop();
let op2;
if (operand2 == "+" || operand2 == "*") {
operand.push(operand2);
op2 = this.calculate(operand);
}
else {
op2 = operand2;
}
let operand1 = operand.pop();
let op1;
if (operand1 == "+" || operand1 == "*") {
operand.push(operand1);
op1 = this.calculate(operand);
}
else {
op1 = operand1;
}
if (operator == "+") {
this.result = parseInt(op1) + parseInt(op2);
}
else if (operator == "*") {
this.result = op1 * op2;
}
return this.result;
}
}
Main.js const Calculator = require("./Calculator.js");
// 1 + 4 * 2
let operand = new Array();
operand.push("1");
operand.push("4");
operand.push("2");
operand.push("*");
operand.push("+");
let cal = new Calculator();
process.stdout.write(cal.calculate(operand) + "\n");
// (1 + 4) * 2
operand.slice(0);
operand.push("1");
operand.push("4");
operand.push("+");
operand.push("2");
operand.push("*");
process.stdout.write(cal.calculate(operand) + "\n");
|
Interpreterパターンを使用した例 IOperand.js module.exports = class IOperand {
getOperand() {}
}
Ingredient.js const IOperand = require("./IOperand.js");
module.exports = class Ingredient extends IOperand {
constructor(operand) {
super();
this.operand = operand;
}
getOperand() {
return this.operand;
}
}
Expression.js const IOperand = require("./IOperand.js");
module.exports = class Expression extends IOperand {
constructor(operator) {
super();
this.operator = operator;
}
getOperand() {
return this.operator.execute().getOperand();
}
}
IOperator.js module.exports = class IOperator {
execute() {}
}
OperationAdd.js const IOperator = require("./IOperator.js");
const Ingredient = require("./Ingredient.js");
module.exports = class OperationAdd extends IOperator {
constructor(operand1, operand2) {
super();
this.operand1 = operand1;
this.operand2 = operand2;
}
execute() {
return new Ingredient(this.operand1.getOperand() + this.operand2.getOperand());
}
}
OperationMultiply.js const IOperator = require("./IOperator.js");
const Ingredient = require("./Ingredient.js");
module.exports = class OperationMultiply extends IOperator {
constructor(operand1, operand2) {
super();
this.operand1 = operand1;
this.operand2 = operand2;
}
execute() {
return new Ingredient(this.operand1.getOperand() * this.operand2.getOperand());
}
}
Main.js const Ingredient = require("./Ingredient.js");
const Expression = require("./Expression.js");
const OperationAdd = require("./OperationAdd.js");
const OperationMultiply = require("./OperationMultiply.js");
let in1 = new Ingredient(1);
let in2 = new Ingredient(4);
let in3 = new Ingredient(2);
// 1 + 4 * 2
let ex1 = new Expression(new OperationMultiply(in2, in3));
let ex2 = new Expression(new OperationAdd(in1, ex1));
process.stdout.write(ex2.getOperand() + "\n");
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, in2));
ex2 = new Expression(new OperationMultiply(ex1, in3));
process.stdout.write(ex2.getOperand() + "\n");
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.pm package Calculator {
sub new {
my ($class) = @_;
my $this = { result => 0 };
return bless $this, $class;
}
sub calculate {
my ($this, $operand) = @_;
if (@{$operand} == 0) {
return $this->{result};
}
my $operator = pop(@{$operand});
my $operand2 = pop(@{$operand});
my $op2 = undef;
if ($operand2 eq "+" || $operand2 eq "*") {
push(@{$operand}, $operand2);
$op2 = $this->calculate($operand);
}
else {
$op2 = operand2;
}
my $operand1 = pop(@{$operand});
my $op1 = undef;
if ($operand1 eq "+" || $operand1 eq "*") {
push(@{$operand}, $operand1);
$op1 = $this->calculate($operand);
}
else {
$op1 = $operand1;
}
if ($operator eq "+") {
$this->{result} = $op1 + $op2;
}
elsif ($operator eq "*") {
$this->{result} = $op1 * $op2;
}
return $this->{result};
}
}
Main.pl use lib qw(./);
use Calculator;
# 1 + 4 * 2
my @operand = ();
push(@operand, "1");
push(@operand, "4");
push(@operand, "2");
push(@operand, "*");
push(@operand, "+");
my $cal = new Calculator();
print $cal->calculate(\@operand) . "\n";
# (1 + 4) * 2
@operand = ();
push(@operand, "1");
push(@operand, "4");
push(@operand, "+");
push(@operand, "2");
push(@operand, "*");
print $cal->calculate(\@operand) . "\n";
|
Interpreterパターンを使用した例 IOperand.pm package class IOperand {
getOperand {}
}
1;
Ingredient.pm package class Ingredient {
use base qw(IOperand);
sub new {
my ($class, $operand) = @_;
my $this = { operand => $operand };
return bless $this, $class;
}
sub getOperand() {
my ($this) = @_;
return $this->{operand};
}
}
1;
Expression.pm package Expression {
use base qw(IOperand);
sub new {
my ($class, $operator) = @_;
my $this = { operator => $operator };
return bless $this, $class;
}
sub getOperand() {
my ($this) = @_;
return $this->{operator}->execute()->getOperand();
}
}
1;
IOperator.pm package IOperator {
sub execute {}
}
1;
OperationAdd.pm package OperationAdd {
use base qw(IOperator);
use Ingredient;
sub new {
my ($class, $operand1, $operand2) = @_;
my $this = { operand1 => $operand1, operand2 => $operand2 };
return bless $this, $class;
}
sub execute() {
my ($this) = @_;
return new Ingredient($this->{operand1}->getOperand()
+ $this->{operand2}->getOperand());
}
}
1;
OperationMultiply.pm package OperationMultiply {
use base qw(IOperator);
use Ingredient;
sub new {
my ($class, $operand1, $operand2) = @_;
my $this = { operand1 => $operand1, operand2 => $operand2 };
return bless $this, $class;
}
sub execute() {
my ($this) = @_;
return new Ingredient($this->{operand1}->getOperand()
* $this->{operand2}->getOperand());
}
}
1;
Main.pl use lib qw(./);
use Ingredient;
use Expression;
use OperationAdd;
use OperationMultiply;
my $in1 = new Ingredient(1);
my $in2 = new Ingredient(4);
my $in3 = new Ingredient(2);
# 1 + 4 * 2
my $ex1 = new Expression(new OperationMultiply($in2, $in3));
my $ex2 = new Expression(new OperationAdd($in1, $ex1));
print $ex2->getOperand() . "\n";
# (1 + 4) * 2
$ex1 = new Expression(new OperationAdd($in1, $in2));
$ex2 = new Expression(new OperationMultiply($ex1, $in3));
print $ex2->getOperand() . "\n";
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.rb class Calculator
def initialize()
@result = 0
end
def calculate(operand)
if operand.size == 0 then
return @result
end
operator = operand.pop()
operand2 = operand.pop()
if operand2 == "+" || operand2 == "*" then
operand.push(operand2)
op2 = calculate(operand)
else
op2 = operand2
end
operand1 = operand.pop()
if operand1 == "+" || operand1 == "*" then
operand.push(operand1)
op1 = calculate(operand)
else
op1 = operand1
end
if operator == "+" then
@result = op1.to_i + op2.to_i
elsif operator == "*" then
@result = op1.to_i * op2.to_i
end
return @result
end
end
Main.rb require './Calculator'
# 1 + 4 * 2
operand = Array.new()
operand.push("1")
operand.push("4")
operand.push("2")
operand.push("*")
operand.push("+")
cal = Calculator.new()
puts cal.calculate(operand)
# (1 + 4) * 2
operand.slice(0)
operand.push("1")
operand.push("4")
operand.push("+")
operand.push("2")
operand.push("*")
puts cal.calculate(operand)
|
Interpreterパターンを使用した例 IOperand.rb class IOperand
def getOperand()
puts "getOperand メソッドを定義してください。"
end
end
Ingredient.rb require './IOperand'
class Ingredient < IOperand
def initialize(operand)
super()
@operand = operand
end
def getOperand()
return @operand
end
end
Expression.rb require './IOperand
class Expression < IOperand
def initialize(operator)
super()
@operator = operator
end
def getOperand()
return @operator.execute().getOperand()
end
end
IOperator.rb class IOperator
def execute()
puts "execute メソッドを定義してください。"
end
end
OperationAdd.rb require './IOperator';
require './Ingredient'
class OperationAdd < IOperator
def initialize(operand1, operand2)
super()
@operand1 = operand1
@operand2 = operand2
end
def execute()
return Ingredient.new(@operand1.getOperand() + @operand2.getOperand())
end
end
OperationMultiply.rb require './IOperator';
require './Ingredient'
class OperationMultiply < IOperator
def initialize(operand1, operand2)
super()
@operand1 = operand1
@operand2 = operand2
end
def execute()
return Ingredient.new(@operand1.getOperand() * @operand2.getOperand())
end
end
Main.rb require './Ingredient'
require './Expression'
require './OperationAdd'
require './OperationMultiply'
in1 = Ingredient.new(1)
in2 = Ingredient.new(4)
in3 = Ingredient.new(2)
# 1 + 4 * 2
ex1 = Expression.new(OperationMultiply.new(in2, in3))
ex2 = Expression.new(OperationAdd.new(in1, ex1))
puts ex2.getOperand()
# (1 + 4) * 2
ex1 = Expression.new(OperationAdd.new(in1, in2))
ex2 = Expression.new(OperationMultiply.new(ex1, in3))
puts ex2.getOperand()
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.py class Calculator:
def __init__(self):
self.result = 0
def calculate(self, operand):
if len(operand) == 0:
return result
operator = operand.pop()
operand2 = operand.pop()
if operand2 == "+" or operand2 == "*":
operand.append(operand2)
op2 = self.calculate(operand)
else:
op2 = operand2
operand1 = operand.pop()
if operand1 == "+" or operand1 == "*":
operand.append(operand1)
op1 = self.calculate(operand)
else:
op1 = operand1
if operator == "+":
self.result = int(op1) + int(op2)
elif (operator == "*":
self.result = int(op1) * int(op2)
return self.result
Main.py from Calculator import Calculator
# 1 + 4 * 2
operand = []
operand.push("1")
operand.push("4")
operand.push("2")
operand.push("*")
operand.push("+")
cal = Calculator()
print(cal.calculate(operand))
# (1 + 4) * 2
operand = []
operand.push("1")
operand.push("4")
operand.push("+")
operand.push("2")
operand.push("*")
print(cal.calculate(operand))
|
Interpreterパターンを使用した例 IOperand.py from abc import ABCMeta, abstractmethod
class IOperand(metaclass=ABCMeta):
def getOperand(self):
pass
Ingredient.py from IOperand import IOperand
class Ingredient(IOperand):
def __init__(self, operand):
self.operand = operand
def getOperand(self):
return self.operand
Expression.py from IOperand import IOperand
class Expression(IOperand):
def __init__(self, operator):
self.operator = operator
def getOperand(self):
return self.operator.execute().getOperand()
IOperator.py from abc import ABCMeta, abstractmethod
class IOperator(metaclass=ABCMeta):
def execute(self):
pass
OperationAdd.py from IOperator import IOperator
from Ingredient import Ingredient
class OperationAdd(IOperator):
def __init__(self, operand1, operand2):
self.operand1 = operand1
self.operand2 = operand2
def execute(self):
return Ingredient(self.operand1.getOperand() + self.operand2.getOperand())
OperationMultiply.py from IOperator import IOperator
from Ingredient import Ingredient
class OperationMultiply(IOperator):
def __init__(self, operand1, operand2):
self.operand1 = operand1;
self.operand2 = operand2;
def execute(self):
return Ingredient(self.operand1.getOperand() * self.operand2.getOperand())
Main.py from Ingredient import Ingredient
from Expression import Expression
from OperationAdd import OperationAdd
from OperationMultiply import OperationMultiply
in1 = Ingredient(1)
in2 = Ingredient(4)
in3 = Ingredient(2)
# 1 + 4 * 2
ex1 = Expression(OperationMultiply(in2, in3))
ex2 = Expression(OperationAdd(in1, ex1))
print(ex2.getOperand())
# (1 + 4) * 2
ex1 = Expression(OperationAdd(in1, in2))
ex2 = Expression(OperationMultiply(ex1, in3))
print(ex2.getOperand())
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.php <?php
class Calculator {
private $result = 0.0;
public function calculate(&$operand) {
if (count($operand) == 0)
return $this->result;
$operator = array_pop($operand);
operand2 = array_pop($operand);
if ($operand2 == "+" || $operand2 == "*") {
array_push($operand, operand2);
$op2 = $this->calculate($operand);
}
else {
$op2 = (double)$operand2;
}
$operand1 = array_pop($operand);
if ($operand1 == "+" || $operand1 == "*") {
array_push($operand, $operand1);
$op1 = $this->calculate($operand);
}
else {
$op1 = (double)$operand1);
}
if ($operator == "+") {
$this->result = $op1 + $op2;
}
else if ($operator == "*") {
$this->result = $op1 * $op2;
}
return $this->result;
}
}
?>
Main.php <?php
require_once('Calculator.php');
$operand = new Stack<String>();
// 1 + 4 * 2
$operand.push("1");
$operand.push("4");
$operand.push("2");
$operand.push("*");
$operand.push("+");
$cal = new Calculator();
print $cal->calculate($operand) . "\n";
// (1 + 4) * 2
array_splice($operand, 0);
$operand.push("1");
$operand.push("4");
$operand.push("+");
$operand.push("2");
$operand.push("*");
print $cal->calculate($operand) . "\n";
?>
|
Interpreterパターンを使用した例 IOperand.php <?php
interface IOperand {
public function getOperand();
}
?>
Ingredient.php <?php
require_once('IOperand.php');
class Ingredient implements IOperand {
private $operand = 0;
public function __construct($operand) {
$this->operand = $operand;
}
public function getOperand() {
return $this->operand;
}
}
?>
Expression.php <?php
require_once('IOperand.php');
class Expression implements IOperand {
private $operator = null;
public function __construct($operator) {
$this->operator = $operator;
}
public function getOperand() {
return $this->operator->execute()->getOperand();
}
}
?>
IOperator.php <?php
interface IOperator {
public function execute();
}
?>
OperationAdd.php <?php
require_once('IOperator.php');
require_once('Ingredient.php');
class OperationAdd implements IOperator {
private $operand1 = null;
private $operand2 = null;
public function __construct($operand1, $operand2) {
$this->operand1 = $operand1;
$this->operand2 = $operand2;
}
public function execute() {
return new Ingredient($this->operand1->getOperand()
+ $this->operand2->getOperand());
}
}
?>
OperationMultiply.php <?php
require_once('IOperator.php');
require_once('Ingredient.php');
class OperationMultiply implements IOperator {
private $operand1 = null;
private $operand2 = null;
public function __construct($operand1, $operand2) {
$this->operand1 = $operand1;
$this->operand2 = $operand2;
}
public function execute() {
return new Ingredient($this->operand1->getOperand()
* $this->operand2->getOperand());
}
}
?>
Main.php <?php
require_once('Ingredient.php');
require_once('Expression.php');
require_once('OperationMultiply.php');
require_once('OperationAdd.php');
$in1 = new Ingredient(1);
$in2 = new Ingredient(4);
$in3 = new Ingredient(2);
// 1 + 4 * 2
$ex1 = new Expression(new OperationMultiply($in2, $in3));
$ex2 = new Expression(new OperationAdd($in1, $ex1));
print $ex2->getOperand() . "\n";
// (1 + 4) * 2
$ex1 = new Expression(new OperationAdd($in1, $in2));
$ex2 = new Expression(new OperationMultiply($ex1, $in3));
print $ex2->getOperand() . "\n";
?>
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を $ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+$ex1 を $ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から $ex2 の getOperand() を呼び出します。どのような演算をするかは、$ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 $ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+$ex1 を計算しようとしますが、$ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか $ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 $ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。$ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+$ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.ts export
class Calculator {
private result:number = 0.0;
public calculate(operand:Array<string>):number {
if (operand.length == 0)
return this.result;
let operator:string = operand.pop();
let operand2:string = operand.pop();
let op2:number;
if (operand2 == "+" || operand2 == "*") {
operand.push(operand2);
op2 = calculate(operand);
}
else {
op2 = parseFloat(operand2);
}
let operand1:string = operand.pop();
let op1:number;
if (operand1 == "+" || operand1 == "*") {
operand.push(operand1);
op1 = this.calculate(operand);
}
else {
op1 = parseFloat(operand1);
}
if (operator == "+") {
this.result = op1 + op2;
}
else if (operator == "*") {
this.result = op1 * op2;
}
return this.result;
}
}
Main.ts import {Calculator} from "./Calculator";
let operand:Array<string> = new Array<string>();
// 1 + 4 * 2
operand.push("1");
operand.push("4");
operand.push("2");
operand.push("*");
operand.push("+");
let cal:Calculator = new Calculator();
process.stdout.write(cal.calculate(operand) + "\n");
// (1 + 4) * 2
operand.slice(0);
operand.push("1");
operand.push("4");
operand.push("+");
operand.push("2");
operand.push("*");
process.stdout.write(cal.calculate(operand) + "\n");
|
Interpreterパターンを使用した例 IOperand.ts export
interface IOperand {
getOperand():number;
}
Ingredient.ts import {IOperand} from "./IOperand";
export
class Ingredient implements IOperand {
private operand:number = 0;
public constructor(operand:number) {
this.operand = operand;
}
public getOperand():number {
return this.operand;
}
}
Expression.ts import {IOperand} from "./IOperand";
import {IOperator} from "./IOperator";
export
class Expression implements IOperand {
private operator:IOperator = null;
public constructor(operator:IOperator) {
this.operator = operator;
}
public getOperand():number {
return this.operator.execute().getOperand();
}
}
IOperator.ts import {IOperand} from "./IOperand";
export
interface IOperator {
execute():IOperand;
}
OperationAdd.ts import {IOperator} from "./IOperator";
import {Ingredient} from "./Ingredient";
import {IOperand} from "./IOperand";
export
class OperationAdd implements IOperator {
private operand1:IOperand;
private operand2:IOperand;
public constructor(operand1:IOperand, operand2:IOperand) {
this.operand1 = operand1;
this.operand2 = operand2;
}
public execute():IOperand {
return new Ingredient(operand1.getOperand() + operand2.getOperand());
}
}
OperationMultiply.ts import {IOperator} from "./IOperator";
import {Ingredient} from "./Ingredient";
import {IOperand} from "./IOperand";
export
class OperationMultiply implements IOperator {
private operand1:IOperand;
private operand2:IOperand;
public constructor(operand1:IOperand, operand2:IOperand) {
this.operand1 = operand1;
this.operand2 = operand2;
}
public execute():IOperand {
return new Ingredient(operand1.getOperand() * operand2.getOperand());
}
}
Main.ts import {Ingredient} from "./Ingredient";
import {Expression} from "./Expression";
import {OperationAdd} from "./OperationAdd";
import {OperationMultiply} from "./OperationMultiply";
let in1:Ingredient = new Ingredient(1);
let in2:Ingredient = new Ingredient(4);
let in3:Ingredient = new Ingredient(2);
// 1 + 4 * 2
let ex1:Expression = new Expression(new OperationMultiply(in2, in3));
let ex2:Expression = new Expression(new OperationAdd(in1, ex1));
process.stdout.write(ex2.getOperand() + "\n");
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, in2));
ex2 = new Expression(new OperationMultiply(ex1, in3));
process.stdout.write(ex2.getOperand() + "\n");
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.swift public class Calculator {
private var result:Double = 0.0
public func calculate(_ operand:inout [String]) -> Double {
if operand == [] {
return result
}
let _operator:String = operand.removeLast()
let operand2:String = operand.removeLast()
let op2:Double = 0.0
if operand2 == "+" || operand2 == "*" {
operand.append(operand2)
op2 = calculate(&operand)
}
else {
op2 = Double(operand2)!
}
let operand1:String = operand.removeLast()
let op1:Double = 0
if operand1 == "+" || operand1 == "*" {
operand.append(operand1)
op1 = calculate(&operand)
}
else {
op1 = Double(operand1)!
}
if _operator == "+" {
result = op1 + op2
}
else if (_operator == "*" {
result = op1 * op2
}
return result
}
}
Main.swift let operand:[String] = []
// 1 + 4 * 2
operand.append("1")
operand.append("4")
operand.append("2")
operand.append("*")
operand.append("+")
let cal:Calculator = Calculator();
print(Int(cal.calculate(&operand)))
// (1 + 4) * 2
operand = []
operand.append("1")
operand.append("4")
operand.append("+")
operand.append("2")
operand.append("*")
print(Int(cal.calculate(&operand)))
|
Interpreterパターンを使用した例 IOperand.swift public protocol IOperand {
func getOperand() -> Double
}
Ingredient.swift public class Ingredient : IOperand {
private var operand:Double = 0
public init(_ operand:Double) {
self.operand = operand
}
public func getOperand() -> Double {
return operand
}
}
Expression.swift public class Expression : IOperand {
private var _operator:IOperator
public init(_ _operator:IOperator) {
self._operator = _operator
}
public func getOperand() -> Double {
return _operator.execute().getOperand()
}
}
IOperator.swift public protocol IOperator {
func execute() -> IOperand
}
OperationAdd.swift public class OperationAdd : IOperator {
private var operand1:IOperand
private var operand2:IOperand
public init(_ operand1:IOperand, _ operand2:IOperand) {
self.operand1 = operand1
self.operand2 = operand2
}
public func execute() -> IOperand {
return Ingredient(operand1.getOperand() + operand2.getOperand())
}
}
OperationMultiply.swift public class OperationMultiply : IOperator {
private var operand1:IOperand
private var operand2:IOperand
public init(_ operand1:IOperand, _ operand2:IOperand) {
self.operand1 = operand1
self.operand2 = operand2
}
public func execute() -> IOperand {
return Ingredient(operand1.getOperand() * operand2.getOperand())
}
}
Main.swift let in1:Ingredient = Ingredient(1)
let in2:Ingredient = Ingredient(4)
let in3:Ingredient = Ingredient(2)
// 1 + 4 * 2
var ex1:Expression = Expression(OperationMultiply(in2, in3))
var ex2:Expression = Expression(OperationAdd(in1, ex1))
print(ex2.getOperand())
// (1 + 4) * 2
ex1 = Expression(OperationAdd(in1, in2))
ex2 = Expression(OperationMultiply(ex1, in3))
print(ex2.getOperand())
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.kt import java.util.Stack
internal class Calculator {
public calculate(operand: Stack<String>) : Double {
if (operand.empty()) return 0.0
val operator = operand.pop() as String
val operand2 = operand.pop() as String
val op2: Double = if (operand2 == "+" || operand2 == "*") {
operand.push(operand2)
calculate(operand)
}
else {
operand2.toDouble()
}
val operand1 = operand.pop() as String
val op1: Double = if (operand1 == "+" || operand1 == "*") {
operand.push(operand1)
calculate(operand)
}
else {
operand1.toDouble()
}
return if (operator == "+") op1 + op2
else if (operator == "*") op1 * op2
else 0.0
}
}
Main.kt import java.util.Stack
fun main() {
var operand = Stack<String>()
// 1 + 4 * 2
operand.push("1")
operand.push("4")
operand.push("2")
operand.push("*")
operand.push("+")
var cal = Calculator()
println(cal.calculate(operand).toInt())
// (1 + 4) * 2
operand.clear()
operand.push("1")
operand.push("4")
operand.push("+")
operand.push("2")
operand.push("*")
println(cal.calculate(operand).toInt())
}
|
Interpreterパターンを使用した例 IOperand.kt interface IOperand {
fun getOperand() : Double
}
Ingredient.kt internal class Ingredient(private val operand: Double) : IOperand {
override fun getOperand(): Double {
return operand
}
}
Expression.kt internal class Expression(val operator: IOperator) : IOperand {
override fun getOperand(): Double {
return operator.execute().getOperand()
}
}
IOperator.kt interface IOperator {
fun execute() : IOperand
}
OperationAdd.kt internal class OperationAdd(private val operand1: IOperand, private val operand2: IOperand) : IOperator {
override fun execute() : IOperand {
return Ingredient(operand1.getOperand() + operand2.getOperand())
}
}
OperationMultiply.kt internal class OperationMultiply(private val operand1: IOperand, private val operand2: IOperand) : IOperator {
override fun execute() : IOperand {
return Ingredient(operand1.getOperand() * operand2.getOperand())
}
}
Main.kt fun main() {
val in1 = Ingredient(1.0)
val in2 = Ingredient(4.0)
val in3 = Ingredient(2.0)
// 1 + 4 * 2
var ex1 = Expression(OperationMultiply(in2, in3))
var ex2 = Expression(OperationAdd(in1, ex1))
println(ex2.getOperand().toInt())
// (1 + 4) * 2
ex1 = Expression(OperationAdd(in1, in2))
ex2 = Expression(OperationMultiply(ex1, in3))
println(ex2.getOperand().toInt())
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.scala import scala.collection.mutable.Stack
class Calculator {
private var result = 0.0
def calculate(operand: Stack[String]) : Double = {
if (operand.isEmpty) return result
val operator = operand.pop()
val operand2 = operand.pop()
var op2: Double = if (operand2 == "+" || operand2 == "*") {
operand.push(operand2)
calculate(operand)
}
else {
operand2.toDouble
}
val operand1 = operand.pop()
var op1: Double = if (operand1 == "+" || operand1 == "*") {
operand.push(operand1)
calculate(operand)
}
else {
operand1.toDouble
}
if (operator == "+") op1 + op2
else if (operator == "*") op1 * op2
else 0.0
}
}
Main.scala import scala.collection.mutable.Stack
object Main {
def main(args: Array[String]) {
val operand = new Stack[String]()
// 1 + 4 * 2
operand.push("1")
operand.push("4")
operand.push("2")
operand.push("*")
operand.push("+")
val cal = new Calculator()
System.out.println(cal.calculate(operand))
// (1 + 4) * 2
operand.clear()
operand.push("1")
operand.push("4")
operand.push("+")
operand.push("2")
operand.push("*")
System.out.println(cal.calculate(operand))
}
}
|
Interpreterパターンを使用した例 IOperand.scala trait IOperand {
def getOperand() : Double
}
Ingredient.scala class Ingredient(val operand: Double) extends IOperand {
def getOperand(): Double = operand
}
Expression.scala class Expression(val operator: IOperator) extends IOperand {
override def getOperand(): Double = operator.execute().getOperand()
}
IOperator.scala trait IOperator {
def execute() : IOperand
}
OperationAdd.scala class OperationAdd(val operand1: IOperand, val operand2: IOperand) extends IOperator {
def execute() = new Ingredient(operand1.getOperand() + operand2.getOperand())
}
OperationMultiply.scala class OperationMultiply(var operand1: IOperand, var operand2: IOperand) extends IOperator {
def execute() = new Ingredient(operand1.getOperand() * operand2.getOperand())
}
Main.scala object Main {
def main(args: Array[String]) {
val in1 = new Ingredient(1.0)
val in2 = new Ingredient(4.0)
val in3 = new Ingredient(2.0)
// 1 + 4 * 2
var ex1 = new Expression(new OperationMultiply(in2, in3))
var ex2 = new Expression(new OperationAdd(in1, ex1))
System.out.println(ex2.getOperand())
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, in2))
ex2 = new Expression(new OperationMultiply(ex1, in3))
System.out.println(ex2.getOperand())
}
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.groovy class Calculator {
private double result = 0.0
double calculate(Stack<String> operand) {
if (operand.empty())
return result
String operator = (String)operand.pop()
String operand2 = (String)operand.pop()
double op2
if (operand2 == "+" || operand2 == "*") {
operand.push(operand2)
op2 = calculate(operand)
}
else {
op2 = Double.parseDouble(operand2)
}
String operand1 = (String)operand.pop()
double op1
if (operand1 == "+" || operand1 == "*") {
operand.push(operand1)
op1 = calculate(operand)
}
else {
op1 = Double.parseDouble(operand1)
}
if (operator == "+") {
result = op1 + op2
}
else if (operator == "*") {
result = op1 * op2
}
return result
}
}
Main.groovy class Main {
static void main(String[] args) {
Stack<String> operand = new Stack<String>()
// 1 + 4 * 2
operand.push("1")
operand.push("4")
operand.push("2")
operand.push("*")
operand.push("+")
Calculator cal = new Calculator()
System.out.println(cal.calculate(operand))
// (1 + 4) * 2
operand.clear()
operand.push("1")
operand.push("4")
operand.push("+")
operand.push("2")
operand.push("*")
System.out.println(cal.calculate(operand))
}
}
|
Interpreterパターンを使用した例 IOperand.groovy interface IOperand {
double getOperand()
}
Ingredient.groovy class Ingredient implements IOperand {
private double operand = 0
Ingredient(double operand) {
this.operand = operand
}
double getOperand() {
return this.operand
}
}
Expression.groovy class Expression implements IOperand {
private IOperator operator = null
Expression(IOperator operator) {
this.operator = operator
}
double getOperand() {
return operator.execute().getOperand()
}
}
IOperator.groovy interface IOperator {
IOperand execute()
}
OperationAdd.groovy class OperationAdd implements IOperator {
private IOperand operand1 = null
private IOperand operand2 = null
OperationAdd(IOperand operand1, IOperand operand2) {
this.operand1 = operand1
this.operand2 = operand2
}
IOperand execute() {
return new Ingredient(operand1.getOperand() + operand2.getOperand())
}
}
OperationMultiply.groovy class OperationMultiply implements IOperator {
private IOperand operand1 = null
private IOperand operand2 = null
OperationMultiply(IOperand operand1, IOperand operand2) {
this.operand1 = operand1
this.operand2 = operand2
}
IOperand execute() {
return new Ingredient(operand1.getOperand() * operand2.getOperand())
}
}
Main.groovy class Main {
static void main(String[] args) {
Ingredient in1 = new Ingredient(1)
Ingredient in2 = new Ingredient(4)
Ingredient in3 = new Ingredient(2)
// 1 + 4 * 2
Expression ex1 = new Expression(new OperationMultiply(in2, in3))
Expression ex2 = new Expression(new OperationAdd(in1, ex1))
System.out.println(ex2.getOperand())
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, in2))
ex2 = new Expression(new OperationMultiply(ex1, in3))
System.out.println(ex2.getOperand())
}
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 Calculator.go import "strconv"
type Calculator struct {}
func (self *Calculator) Calculate(operand []string) (float32, []string) {
var result float32 = 0
if len(operand) == 0 {
return result, nil
}
operator, operand := pop(operand)
operand2, operand := pop(operand)
var op2 float32
if operand2 == "+" || operand2 == "*" {
operand = append(operand, operand2)
op2, operand = self.Calculate(operand)
} else {
opx, _ := strconv.ParseFloat(operand2, 32)
op2 = float32(opx)
}
operand1, operand := pop(operand)
var op1 float32
if operand1 == "+" || operand1 == "*" {
operand = append(operand, operand1)
op1, operand = self.Calculate(operand)
} else {
opx, _ := strconv.ParseFloat(operand1, 32)
op1 = float32(opx)
}
if operator == "+" {
result = op1 + op2
} else if operator == "*" {
result = op1 * op2
}
return result, operand
}
func pop(stack []string) (string, []string) {
var n = len(stack)-1
var data = stack[n]
stack = stack[0:n]
return data, stack
}
func NewCalculator() *Calculator {
return &Calculator{}
}
Main.go import "fmt"
func main() {
operand = []String{}
// 1 + 4 * 2
operand = append(operand, "1")
operand = append(operand, "4")
operand = append(operand, "2")
operand = append(operand, "*")
operand = append(operand, "+")
var cal = NewCalculator()
var val, _ = cal.Calculate(operand)
fmt.Println(val)
// (1 + 4) * 2
operand = operand[0:0]
operand = append(operand, "1")
operand = append(operand, "4")
operand = append(operand, "+")
operand = append(operand, "2")
operand = append(operand, "*")
val, _ = cal.Calculate(operand)
fmt.Println(val)
}
|
Interpreterパターンを使用した例 IOperand.go type IOperand interface {
GetOperand() float32
}
Ingredient.go type Ingredient struct {
IOperand {
operand float32
}
func (self *Ingredient) GetOperand() float32 {
return self.operand
}
func NewIngredient(operand float32) *Ingredient {
return &Ingredient {
operand: operand,
}
}
Expression.go type Expression struct {
operator IOperand {
}
func (self *Expression) GetOperand() float32 {
return self.operator.Execute().GetOperand()
}
func NewExpression(operator IOperator) *Expression {
return &Expression {
operator: operator,
}
}
IOperator.go type IOperator interface {
Execute() IOperand
}
OperationAdd.go type OperationAdd struct {
IOperator
operand1 IOperand
operand2 IOperand
}
func (self *OperationAdd) Execute() IOperand {
return NewIngredient(self.operand1.GetOperand() + self.operand2.GetOperand())
}
func NewOperationAdd(operand1 IOperand, operand2 IOperand) IOperator {
return &OperationAdd {
operand1: operand1,
operand2: operand2,
}
}
OperationMultiply.go type OperationMultiply struct {
IOperator
operand1 IOperand
operand2 IOperand
}
func (self *OperationMultiply) Execute() IOperand {
return NewIngredient(self.operand1.GetOperand() + self.operand2.GetOperand())
}
func NewOperationMultiply(operand1 IOperand, operand2 IOperand) IOperator {
return &OperationMultiply {
operand1: operand1,
operand2: operand2,
}
}
Main.go import (
"fmt"
"strconv"
)
func main() {
var in1 = NewIngredient(1)
var in2 = NewIngredient(4)
var in3 = NewIngredient(2)
// 1 + 4 * 2
var ex1 = NewExpression(NewOperationMultiply(in2, in3))
NewExpression ex2 = NewExpression(NewOperationAdd(in1, ex1))
fmt.Println(strconv.FormatFloat(float64(ex2.GetOperand()), 'f', 1, 32))
// (1 + 4) * 2
ex1 = NewExpression(NewOperationAdd(in1, in2))
ex2 = NewExpression(NewOperationMultiply(ex1, in3))
fmt.Println(strconv.FormatFloat(float64(ex2.GetOperand()), 'f', 1, 32))
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |
|
Interpreterパターンを使用しない例 calculator.d import std.conv;
public class Calculator {
private double result = 0.0;
public double calculate(ref string[] operand) {
if (operand.length == 0)
return result;
string operator = operand[operand.length-1]; operand = operand[0..operand.length-1]; // pop
string operand2 = operand[operand.length-1]; operand = operand[0..operand.length-1]; // pop
double op2;
if (operand2 == "+" || operand2 == "*") {
operand ~= operand2;
op2 = calculate(operand);
}
else {
op2 = parse!(double)(operand2);
}
string operand1 = operand[operand.length-1]; operand = operand[0..operand.length-1]; // pop
double op1;
if (operand1 == "+" || operand1 == "*") {
operand ~= operand1;
op1 = calculate(operand);
}
else {
op1 = parse!(double)(operand1);
}
if (operator = "+") {
result = op1 + op2;
}
else if (operator = "*") {
result = op1 * op2;
}
return result;
}
}
main.d import std.stdio;
import calculator;
int main() {
string[] operand;
// 1 + 4 * 2
operand ~= "1";
operand ~= "4";
operand ~= "2";
operand ~= "*";
operand ~= "+";
Calculator cal = new Calculator();
writeln(cal.calculate(operand));
// (1 + 4) * 2
operand = [];
operand ~= "1";
operand ~= "4";
operand ~= "+";
operand ~= "2";
operand ~= "*";
writeln(cal.calculate(operand));
return 0;
}
|
Interpreterパターンを使用した例 ioperand.d public interface IOperand {
double getOperand();
}
ingredient.d import ioperand;
public class Ingredient : IOperand {
private double operand = 0;
public this(in double operand) {
this.operand = operand;
}
public double getOperand() {
return operand;
}
}
expression.d import ioperand;
import ioperator;
public class Expression : IOperand {
private IOperator operator = null;
public this(IOperator operator) {
this.operator = operator;
}
public double getOperand() {
return operator.execute().getOperand();
}
}
ioperator.d import ioperand;
public interface IOperator {
public IOperand execute();
}
operationadd.d import ioperator;
import ioperand;
import ingredient;
public class OperationAdd : IOperator {
private IOperand operand1 = null;
private IOperand operand2 = null;
public this(IOperand operand1, IOperand operand2) {
this.operand1 = operand1;
this.operand2 = operand2;
}
public IOperand execute() {
return new Ingredient(operand1.getOperand() + operand2.getOperand());
}
}
operationmultiply.d import ioperator;
import ioperand;
import ingredient;
public class OperationMultiply : IOperator {
private IOperand operand1 = null;
private IOperand operand2 = null;
public this(IOperand operand1, IOperand operand2) {
this.operand1 = operand1;
this.operand2 = operand2;
}
public IOperand execute() {
return new Ingredient(operand1.getOperand() * operand2.getOperand());
}
}
main.d import std.stdio;
import ingredient;
import expression;
import operationadd;
import operationmultiply;
int main() {
Ingredient in1 = new Ingredient(1);
Ingredient in2 = new Ingredient(4);
Ingredient in3 = new Ingredient(2);
// 1 + 4 * 2
Expression ex1 = new Expression(new OperationMultiply(in2, in3));
Expression ex2 = new Expression(new OperationAdd(in1, ex1));
writeln(ex2.getOperand());
// (1 + 4) * 2
ex1 = new Expression(new OperationAdd(in1, in2));
ex2 = new Expression(new OperationMultiply(ex1, in3));
writeln(ex2.getOperand());
return 0;
}
|
|
この例では、演算式を解析し、逆ポーランド記法で書きなおされています。これを計算して答えを得ます。 逆ポーランド記法 1 + 4 * 2 → 1 4 2 * + (1 + 4) * 2 → 1 4 + 2 * 取り出したものが演算子だったら、スタックから次の2つを取り出して演算します。しかし、取り出した中にまた演算子があったら、それは式なので、またスタックから次の2つを取り出して...というように繰り返します。ここでは、再起呼び出しを利用しています。計算はうまくできているようです。 しかし、この後減算と除算を追加しようとしたら、calculate() に新たに減算と除算のための if 文を追加しなければなりません。これでは拡張性が良いとは言えません。 |
Interpreter パターンでは、項が数値でも式でも同じようにオブジェクトとして扱っています。 例えば、1 + 4 * 2 は、 + まず、4*2 を ex1 という Expression インスタンスに作成します。operator は OperationMultiply です。 次に、1+ex1 を ex2 という Expression インスタンスに作成します。operator は OperationAdd です。 そして、計算結果を求めるために、main から ex2 の getOperand() を呼び出します。どのような演算をするかは、ex2 が知っています(Expression の operator)。OperationAdd ならば加算ですし、OperationMultiply ならば乗算です。 ex2 の持つ IOperator は OperationAdd です。OperationAdd の excute() を呼んで、1+ex1 を計算しようとしますが、ex1 が式なのでさらにその値を計算(getOperand())します。このとき、getOperand() は、項(1 とか ex1)が式(Expression)の場合は、演算をして(execute)から、その結果を返しています。また、数値(Ingredient)の場合は、そのまま値を返しています。 ex1 は式なので、Expression インスタンスの getOperand() が呼び出されます。ex1 の持つ IOperator は OperationMultiply です。OperationMultiply の excute() を呼んで、4*2 が計算され 8 が戻り値となります。 その結果、1+ex1 が 1+8 となり、計算され 9 が戻り値となり、表示されます。 Interpreter パターンであれば、この後、減算と除算を追加する場合でも、IOperator を継承して作成するだけですみます。 |