Chain of Responsibilityパターン
処理できるクラスが現れるまで順送りする
chain は「鎖」、responsibility は「責任」を意味します。したがって、 Chain of Responsibility は、「責任の鎖」と訳すことができます。Chain of Responsibility パターンとは、「責任」を負ったものが、「鎖」状につながれた状態をイメージさせるパターンです。
例えば、お客さんからクレームがあった場合、その処理を自分ができるのならしますが、よく分からないときはより詳しい人とかその客の担当にお願いします。お願いされた人は、対応できるものならしますが、対応できないものについては、課長にお願いすることになります。当然課長が対応できないものであればより上位の責任者に委ねられます。Chain of Responsibility パターンは、「責任者」を「鎖状」につないでおき、「いずれかの段階」で、「誰か」が処理をすることを表現するようなパターンです。

このように、メッセージを他のクラスのオブジェクトに送って処理してもらうことを、「委譲」と呼びます。すなわち、Chain of Responsibilityパターンを実現するには、メッセージの送り先のオブジェクトのポインタ(「アドレス」や「参照」とも呼ぶ)を知っている必要があります。具体的には、クラスのメンバの中に、送り先のオブジェクトのポインタを格納するフィールドを用意しておくわけです。
まず、自身で処理できなければ次のサブクラスに回していきます。そして最初に条件に合致したクラスが処理を行い、あとのクラスには回されません。処理の優先順位を決める連鎖リストは呼び出し側で指定する必要があります。
別バリエーションとして、最後にデフォルトを持ってきて必ず何らかの処理をさせるパターンや合致する複数の条件すべての処理を可能にするパターンがあります。
スーパークラスおよび実際の処理のサブクラスは変更する必要がなく、別の処理が必要になればサブクラスを追加すればよい点がこのパターンの特徴です。
ただし、ある条件に対する処理が1対1で決まっている場合、たらい回しにしている分、呼び出しのオーバーヘッドがあります。毎回チェーンをたどっていくため、処理速度が遅くなることが考えられます。速度重視のプログラムが必要なのか、柔軟性が求められるのか、状況によって判断する必要がありそうです。
例題
yyyy/mm/dd
yyyymmdd
yyyy年mm月dd日
日付をあらわす文字列を日付型に変換するクラスを作成しなさい。日付の形式は次のとおりです。
実行結果
2019-05-02
2019-05-03
|
Chain of Responsibilityパターンを使用しない例 StringToDate.java public class StringToDate {
public Date getDate(String str) {
if (str.length() == 10) {
// yyyy/MM/dd
int y = Integer.parseInt(str.substring(0, 4));
int m = Integer.parseInt(str.substring(5, 7));
int d = Integer.parseInt(str.substring(8));
Calendar cal = Calendar.getInstance();
cal.set(y, m - 1, d, 0, 0, 0);
return cal.getTime();
}
else if (str.length() == 8) {
// yyyyMMdd
int y = Integer.parseInt(str.substring(0, 4));
int m = Integer.parseInt(str.substring(4, 6));
int d = Integer.parseInt(str.substring(6));
Calendar cal = Calendar.getInstance();
cal.set(y, m - 1, d, 0, 0, 0);
return cal.getTime();
}
else if (str.length() == 11) {
// yyyy年mm月dd日
int y = Integer.parseInt(str.substring(0, 4));
int m = Integer.parseInt(str.substring(5, 7));
int d = Integer.parseInt(str.substring(8, 10));
Calendar cal = Calendar.getInstance();
cal.set(y, m - 1, d, 0, 0, 0);
return cal.getTime();
}
return null;
}
}
Main.java public class Main {
public static void main(String[] args) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
StringToDate sdt = new StringToDate();
Date dt1 = sdt.getDate("2019/05/01");
Date dt2 = sdt.getDate("20190502");
Date dt3 = sdt.getDate("2019年05月03日");
System.out.println(df.format(dt1));
System.out.println(df.format(dt2));
System.out.println(df.format(dt3));
}
}
|
Chain of Responsibilityパターンを使用した例 StringToDate.java public abstract class StringToDate {
private StringToDate next = null;
public StringToDate setNext(StringToDate next) {
this.next = next;
return next;
}
public Date toDate(String str) {
Date dt = resolve(str);
if (dt != null) {
return dt;
}
else if (next != null) {
return next.toDate(str);
}
else {
return null;
}
}
protected abstract Date resolve(String str);
}
SlashDelimitDate.java public class SlashDelimitDate extends StringToDate {
protected Date resolve(String str) {
if (str.length() == 10) {
// yyyy/MM/dd
int y = Integer.parseInt(str.substring(0, 4));
int m = Integer.parseInt(str.substring(5, 7));
int d = Integer.parseInt(str.substring(8));
Calendar cal = Calendar.getInstance();
cal.set(y, m - 1, d, 0, 0, 0);
return cal.getTime();
}
else {
return null;
}
}
}
NonDelimitDate.java public class NonDelimitDate extends StringToDate {
protected Date resolve(String str) {
if (str.length() == 8) {
// yyyyMMdd
int y = Integer.parseInt(str.substring(0, 4));
int m = Integer.parseInt(str.substring(4, 6));
int d = Integer.parseInt(str.substring(6));
Calendar cal = Calendar.getInstance();
cal.set(y, m - 1, d, 0, 0, 0);
return cal.getTime();
}
else {
return null;
}
}
}
KanjiDelimitDate.java public class KanjiDelimitDate extends StringToDate {
protected Date resolve(String str) {
if (str.length() == 11) {
// yyyy年mm月dd日
int y = Integer.parseInt(str.substring(0, 4));
int m = Integer.parseInt(str.substring(5, 7));
int d = Integer.parseInt(str.substring(8, 10));
Calendar cal = Calendar.getInstance();
cal.set(y, m - 1, d, 0, 0, 0);
return cal.getTime();
}
else {
return null;
}
}
}
Main.java public class Main {
public static void main(String[] args) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd");
SlashDelimitDate sdt = new SlashDelimitDate();
NonDelimitDate ndt = new NonDelimitDate();
KanjiDelimitDate kdt = new KanjiDelimitDate();
sdt.setNext(ndt).setNext(kdt);
Date dt1 = sdt.toDate("2019/05/01");
Date dt2 = sdt.toDate("20190502");
Date dt3 = sdt.toDate("2019年05月03日");
System.out.println(df.format(dt1));
System.out.println(df.format(dt2));
System.out.println(df.format(dt3));
}
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 stringToDate.h #include <string>
#include <ctime>
class StringToDate
{
private:
tm dt;
int strtoi(std::string);
public:
StringToDate(void);
virtual ~StringToDate(void);
tm getDate(std::string str);
}; stringToDate.cpp #include <sstream>
#include "stringToDate.h"
using namespace std;
StringToDate::StringToDate(void) {}
StringToDate::~StringToDate(void) {}
struct tm StringToDate::getDate(string str) {
int y, m, d;
if (str.length() == 10) {
// yyyy/MM/dd
y = strtoi(str.substr(0, 4));
m = strtoi(str.substr(5, 2));
d = strtoi(str.substr(8));
}
else if (str.length() == 8) {
// yyyyMMdd
y = strtoi(str.substr(0, 4));
m = strtoi(str.substr(4, 2));
d = strtoi(str.substr(6));
}
else if (str.length() == 14) {
// yyyy年mm月dd日
y = strtoi(str.substr(0, 4));
m = strtoi(str.substr(6, 2));
d = strtoi(str.substr(10, 2));
}
dt = { 0, 0 ,0 ,d ,m-1 , y - 1900 };
return dt;
}
int StringToDate::strtoi(string s) {
stringstream ss;
int n;
ss << s;
ss >> n;
return n;
}
main.cpp #include <iostream>
using namespace std;
#include "stringToDate.h"
void print(struct tm dt) {
time_t currenttime = mktime(&dt);
char str[100];
std::strftime(str, sizeof(str), "%Y-%m-%d", std::localtime(¤ttime));
cout << str << endl;
}
int main() {
StringToDate sdt;
tm dt1 = sdt.getDate("2019/05/01");
tm dt2 = sdt.getDate("20190502");
tm dt3 = sdt.getDate("2019年05月03日");
print(dt1);
print(dt2);
print(dt3);
return 0;
}
|
Chain of Responsibilityパターンを使用した例 stringToDate.h #include <string>
#include <ctime>
class StringToDate {
private:
StringToDate* next;
protected:
tm dt;
int strtoi(std::string);
public:
StringToDate(void);
virtual ~StringToDate(void);
StringToDate* setNext(StringToDate*);
tm toDate(std::string);
virtual tm resolve(std::string) = 0;
}; stringToDate.cpp #include <sstream>
#include "stringToDate.h"
using namespace std;
StringToDate::StringToDate(void) : next(NULL) {}
StringToDate::~StringToDate(void) {}
tm StringToDate::toDate(string str) {
dt = resolve(str);
if (dt.tm_year != 0) { return dt; }
else if (next != NULL) {return next->toDate(str); }
else { dt.tm_year = 0; return dt; }
}
StringToDate* StringToDate::setNext(StringToDate* next) {
this->next = next;
return next;
}
int StringToDate::strtoi(string s) {
stringstream ss;
int n;
ss << s;
ss >> n;
return n;
}
slashDelimitDate.h #include "stringtodate.h"
class SlashDelimitDate : public StringToDate
{
public:
SlashDelimitDate(void);
virtual ~SlashDelimitDate(void);
tm resolve(std::string);
}; slashDelimitDate.cpp #include "slashDelimitDate.h"
using namespace std;
SlashDelimitDate::SlashDelimitDate(void) {}
SlashDelimitDate::~SlashDelimitDate(void) {}
tm SlashDelimitDate::resolve(string str) {
if (str.length() == 10) {
// yyyy/MM/dd
int y = strtoi(str.substr(0, 4));
int m = strtoi(str.substr(5, 2));
int d = strtoi(str.substr(8));
dt = { 0, 0 ,0 ,d ,m-1 , y - 1900 };
}
else {
dt.tm_year = 0;
}
return dt;
}
nonDelimitDate.h #include "stringtodate.h"
class NonDelimitDate : public StringToDate
{
public:
NonDelimitDate(void);
virtual ~NonDelimitDate(void);
tm resolve(std::string);
}; nonDelimitDate.cpp #include <sstream>
#include "nonDelimitDate.h"
using namespace std;
NonDelimitDate::NonDelimitDate(void) {}
NonDelimitDate::~NonDelimitDate(void) {}
tm NonDelimitDate::resolve(string str) {
stringstream ss;
if (str.length() == 8) {
// yyyy/MM/dd
int y = strtoi(str.substr(0, 4));
int m = strtoi(str.substr(4, 2));
int d = strtoi(str.substr(6));
dt = { 0, 0 ,0 ,d ,m-1 , y - 1900 };
}
else {
dt.tm_year = 0;
}
return dt;
}
kanjiDelimitDate.h #include "stringtodate.h"
class KanjiDelimitDate : public StringToDate
{
public:
KanjiDelimitDate(void);
virtual ~KanjiDelimitDate(void);
tm resolve(std::string);
}; kanjiDelimitDate.cpp #include <sstream>
#include "kanjiDelimitDate.h"
using namespace std;
KanjiDelimitDate::KanjiDelimitDate(void) {}
KanjiDelimitDate::~KanjiDelimitDate(void) {}
tm KanjiDelimitDate::resolve(string str) {
stringstream ss;
if (str.length() == 14) {
// yyyy/MM/dd
int y = strtoi(str.substr(0, 4));
int m = strtoi(str.substr(6, 2));
int d = strtoi(str.substr(10));
dt = { 0, 0 ,0 ,d ,m-1 , y - 1900 };
}
else {
dt.tm_year = 0;
}
return dt;
}
main.cpp #include <iostream>
using namespace std;
#include "stringToDate.h"
#include "slashDelimitDate.h"
#include "nonDelimitDate.h"
#include "kanjiDelimitDate.h"
void print(struct tm dt) {
time_t currenttime = mktime(&dt);
char str[100];
std::strftime(str, sizeof(str), "%Y-%m-%d", std::localtime(¤ttime));
cout << str << endl;
}
int main() {
SlashDelimitDate sdt;
NonDelimitDate ndt;
KanjiDelimitDate kdt;
sdt.setNext(&ndt)->setNext(&kdt);
tm dt1 = sdt.toDate("2019/05/01");
tm dt2 = sdt.toDate("20190502");
tm dt3 = sdt.toDate("2019年05月03日");
print(dt1);
print(dt2);
print(dt3);
return 0;
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.cs class StringToDate
{
public DateTime? GetDate(string str)
{
if (str.Length == 10)
{
// yyyy/MM/dd
int y = int.Parse(str.Substring(0, 4));
int m = int.Parse(str.Substring(5, 2));
int d = int.Parse(str.Substring(8));
return new DateTime(y, m, d);
}
else if (str.Length == 8)
{
// yyyyMMdd
int y = int.Parse(str.Substring(0, 4));
int m = int.Parse(str.Substring(4, 2));
int d = int.Parse(str.Substring(6));
return new DateTime(y, m, d);
}
else if (str.Length == 11)
{
// yyyy年MM月dd日
int y = int.Parse(str.Substring(0, 4));
int m = int.Parse(str.Substring(5, 2));
int d = int.Parse(str.Substring(8, 2));
return new DateTime(y, m, d);
}
else
return null;
}
} Program.cs class Program
{
static void Main(string[] args)
{
StringToDate sdt = new StringToDate();
DateTime? dt1 = sdt.GetDate("2119/05/01");
DateTime? dt2 = sdt.GetDate("21190502");
DateTime? dt3 = sdt.GetDate("2119年05月03日");
Console.WriteLine(((DateTime)dt1).ToString("yyyy-MM-dd"));
Console.WriteLine(((DateTime)dt2).ToString("yyyy-MM-dd"));
Console.WriteLine(((DateTime)dt3).ToString("yyyy-MM-dd"));
}
}
|
Chain of Responsibilityパターンを使用した例 StringToDate.cs abstract class StringToDate
{
private StringToDate nextDate = null;
public StringToDate SetNext(StringToDate nx)
{
nextDate = nx;
return nx;
}
public StringToDate? ToDate(string str)
{
StringToDate? dt = Resolve(str);
if (dt != null) return dt;
if (nextDate != null) return nextDate.ToDate(str);
return null;
}
public abstract StringToDate? Resolve(string str);
} SlashDelimitDate.cs class SlashDelimitDate : StringToDate
{
public override StringToDate? Resolve(string str)
{
if (str.Length == 10)
{
// yyyy/MM/dd
int y = int.Parse(str.Substring(0, 4));
int m = int.Parse(str.Substring(5, 2));
int d = int.Parse(str.Substring(8));
return new DateTime(y, m, d);
}
else return null;
}
} NonDelimitDate.cs class NonDelimitDate : StringToDate
{
public override StringToDate? Resolve(string str)
{
if (str.Length == 8)
{
// yyyyMMdd
int y = int.Parse(str.Substring(0, 4));
int m = int.Parse(str.Substring(4, 2));
int d = int.Parse(str.Substring(6));
return new DateTime(y, m, d);
}
else return null;
}
} KanjiDelimitDate.cs class KanjiDelimitDate : StringToDate
{
public override StringToDate? Resolve(string str)
{
if (str.Length == 11)
{
// yyyy年MM月dd日
int y = int.Parse(str.Substring(0, 4));
int m = int.Parse(str.Substring(5, 2));
int d = int.Parse(str.Substring(8, 2));
return new DateTime(y, m, d);
}
else return null;
}
} Program.cs class Program
{
static void Main(string[] args)
{
StringToDate sdt = new SlashDelimitDate();
StringToDate ndt = new NonDelimitDate();
StringToDate kdt = new KanjiDelimitDate();
sdt.SetNext(ndt).SetNext(kdt);
DateTime? dt1 = sdt.ToDate("2019/05/01");
DateTime? dt2 = sdt.ToDate("20190502");
DateTime? dt3 = sdt.ToDate("2019年05月03日");
Console.WriteLine(((DateTime)dt1).ToString("yyyy-MM-dd"));
Console.WriteLine(((DateTime)dt2).ToString("yyyy-MM-dd"));
Console.WriteLine(((DateTime)dt3).ToString("yyyy-MM-dd"));
}
}
|
|
日付型への変換メソッド(GetDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの ToDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityを使用しない例 StringToDate.vb Public Class StringToDate
Public Function GetDate(ByVal str As String) As Date
If str.Length = 10 Then
' yyyy/MM/dd
Dim y As Integer = str.Substring(0, 4)
Dim m As Integer = str.Substring(5, 2)
Dim d As Integer = str.Substring(8)
Return New Date(y, m, d)
ElseIf str.Length = 8 Then
' yyyyMMdd
Dim y As Integer = str.Substring(0, 4)
Dim m As Integer = str.Substring(4, 2)
Dim d As Integer = str.Substring(6)
Return New Date(y, m, d)
ElseIf str.Length = 11 Then
' yyyy年MM月dd日
Dim y As Integer = str.Substring(0, 4)
Dim m As Integer = str.Substring(5, 2)
Dim d As Integer = str.Substring(8, 2)
Return New Date(y, m, d)
Else
Return Nothing
End If
End Function
End Class
Program.vb Module Main
Sub Main()
Dim sdt As StringToDate = New StringToDate()
Dim dt1 As Date = sdt.GetDate("2119/05/01")
Dim dt2 As Date = sdt.GetDate("20190502")
Dim dt3 As Date = sdt.GetDate("2019年05月03日")
Console.WriteLine(dt1.ToString("yyyy-MM-dd"))
Console.WriteLine(dt2.ToString("yyyy-MM-dd"))
Console.WriteLine(dt3.ToString("yyyy-MM-dd"))
End Sub
End Module
|
Chain of Responsibilityパターンを使用した例 StringToDate.vb Public MustInherit Class StringToDate
Private nextDate As StringToDate = Nothing
Public Function SetNext(ByVal nx As StringToDate) As StringToDate
nextDate = nx
Return nx
End Function
Public Function ToDate(ByVal str As String) As Date
Dim dt As Date = Resolve(str)
If dt <> Nothing Then Return dt
If Not nextDate.Equals(Nothing) Then Return nextDate.toDate(str)
Return Nothing
End Function
Public MustOverride Function Resolve(ByVal str As String) As Date
End Class
SlashDelimitDate.vb Public Class SlashDelimitDate
Inherits StringToDate
Public Overrides Function Resolve(ByVal str As String) As Date
If str.Length = 10 Then
' yyyy/MM/dd
Dim y As Integer = str.Substring(0, 4)
Dim m As Integer = str.Substring(5, 2)
Dim d As Integer = str.Substring(8)
Return New Date(y, m, d)
Else
Return Nothing
End If
End Function
End Class
NonDelimitDate.vb Public Class NonDelimitDate
Inherits StringToDate
Public Overrides Function Resolve(ByVal str As String) As Date
If str.Length = 8 Then
' yyyyMMdd
Dim y As Integer = str.Substring(0, 4)
Dim m As Integer = str.Substring(4, 2)
Dim d As Integer = str.Substring(6)
Return New Date(y, m, d)
Else
Return Nothing
End If
End Function
End Class
KanjiDelimitDate.vb Public Class KanjiDelimitDate
Inherits StringToDate
Public Overrides Function Resolve(ByVal str As String) As Date
If str.Length = 11 Then
' yyyy年MM月dd日
Dim y As Integer = str.Substring(0, 4)
Dim m As Integer = str.Substring(5, 2)
Dim d As Integer = str.Substring(8, 2)
Return New Date(y, m, d)
Else
Return Nothing
End If
End Function
End Class
Program.vb Module Main
Sub Main()
Dim sdt As SlashDelimitDate = New SlashDelimitDate()
Dim ndt As NonDelimitDate = New NonDelimitDate()
Dim kdt As KanjiDelimitDate = New KanjiDelimitDate()
sdt.setNext(ndt).setNext(kdt)
Dim dt1 As Date = sdt.toDate("2019/05/01")
Dim dt2 As Date = sdt.toDate("20190502")
Dim dt3 As Date = sdt.toDate("2019年05月03日")
Console.WriteLine(dt1.ToString("yyyy-MM-dd"))
Console.WriteLine(dt2.ToString("yyyy-MM-dd"))
Console.WriteLine(dt3.ToString("yyyy-MM-dd"))
End Sub
End Module
|
|
日付型への変換メソッド(GetDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの ToDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.js module.exports = class StringToDate {
getDate(str) {
if (str.length == 10) {
// yyyy/MM/dd
let y = Number.parseInt(str.substring(0, 4));
let m = Number.parseInt(str.substring(5, 7));
let d = Number.parseInt(str.substring(8));
return new Date(y, m - 1, d);
}
else if (str.length == 8) {
// yyyyMMdd
let y = Number.parseInt(str.substring(0, 4));
let m = Number.parseInt(str.substring(4, 6));
let d = Number.parseInt(str.substring(6));
return new Date(y, m - 1, d);
}
else if (str.length == 11) {
// yyyy年mm月dd日
let y = Number.parseInt(str.substring(0, 4));
let m = Number.parseInt(str.substring(5, 7));
let d = Number.parseInt(str.substring(8, 10));
return new Date(y, m - 1, d);
}
return null;
}
} Main.js const StringToDate = require("./StringToDate.js");
function toString(dt) {
return dt.getFullYear() + "-"
+ ('0' + (dt.getMonth() + 1)).slice(-2) + "-"
+ ('0' + dt.getDate()).slice(-2);
}
let sdt = new StringToDate();
let dt1 = sdt.getDate("2019/05/01");
let dt2 = sdt.getDate("20190502");
let dt3 = sdt.getDate("2019年05月03日");
process.stdout.write(toString(dt1) + "\n");
process.stdout.write(toString(dt2) + "\n");
process.stdout.write(toString(dt3) + "\n");
|
Chain of Responsibilityパターンを使用した例 StringToDate.js module.exports = class StringToDate {
constructor() {}
setNext(next) {
this.next = next;
return next;
}
toDate(str) {
let dt = this.resolve(str);
if (dt != null) {
return dt;
}
else if (this.next != null) {
return this.next.toDate(str);
}
else {
return null;
}
}
resolve(str) {
console.log("resolve メソッドを定義してください。");
}
}
SlashDelimitDate.js const StringToDate = require("./StringToDate.js");
module.exports = class SlashDelimitDate extends StringToDate {
resolve(str) {
if (str.length == 10) {
// yyyy/MM/dd
let y = Number.parseInt(str.substring(0, 4));
let m = Number.parseInt(str.substring(5, 7));
let d = Number.parseInt(str.substring(8));
return new Date(y, m - 1, d);
}
else {
return null;
}
}
}
NonDelimitDate.js const StringToDate = require("./StringToDate.js");
module.exports = class NonDelimitDate extends StringToDate {
resolve(str) {
if (str.length == 8) {
// yyyyMMdd
let y = Number.parseInt(str.substring(0, 4));
let m = Number.parseInt(str.substring(4, 6));
let d = Number.parseInt(str.substring(6));
return new Date(y, m - 1, d);
}
else {
return null;
}
}
}
KanjiDelimitDate.js const StringToDate = require("./StringToDate.js");
module.exports = class KanjiDelimitDate extends StringToDate {
resolve(str) {
if (str.length == 11) {
// yyyy年mm月dd日
let y = Number.parseInt(str.substring(0, 4));
let m = Number.parseInt(str.substring(5, 7));
let d = Number.parseInt(str.substring(8, 10));
return new Date(y, m - 1, d);
}
else {
return null;
}
}
} Main.js const SlashDelimitDate = require("./SlashDelimitDate.js");
const NonDelimitDate = require("./NonDelimitDate.js");
const KanjiDelimitDate = require("./KanjiDelimitDate.js");
function toString(dt) {
return dt.getFullYear() + "-"
+ ('0' + (dt.getMonth() + 1)).slice(-2) + "-"
+ ('0' + dt.getDate()).slice(-2);
}
let sdt = new SlashDelimitDate();
let sdt = new SlashDelimitDate();
let ndt = new NonDelimitDate();
let kdt = new KanjiDelimitDate();
sdt.setNext(ndt).setNext(kdt);
let dt1 = sdt.toDate("2019/05/01");
let dt2 = sdt.toDate("20190502");
let dt3 = sdt.toDate("2019年05月03日");
process.stdout.write(toString(dt1) + "\n");
process.stdout.write(toString(dt2) + "\n");
process.stdout.write(toString(dt3) + "\n");
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.pm package StringToDate {
use DateTime;
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub getDate {
my ($this, $str) = @_;
if (length $str == 10) {
# yyyy/MM/dd
my $y = 0 + substr($str, 0, 4);
my $m = 0 + substr($str, 5, 2);
my $d = 0 + substr($str, 8, 2);
return new DateTime( year=>$y, month=>$m, day=>$d );
}
else if (length $str == 8) {
# yyyyMMdd
my $y = 0 + substr($str, 0, 4);
my $m = 0 + substr($str, 4, 2);
my $d = 0 + substr($str, 6, 2);
return new DateTime( year=>$y, month=>$m, day=>$d );
}
else if (length $str == 17) {
# yyyy年mm月dd日
my $y = 0 + substr($str, 0, 4);
my $m = 0 + substr($str, 7, 2);
my $d = 0 + substr($str, 12, 2);
return newDateTime( year=>$y, month=>$m, day=>$d );
}
return null;
}
} Main.pl use lib qw(./);
use StringToDate;
my $sdt = new StringToDate();
my $dt1 = $sdt->getDate("2019/05/01");
my $dt2 = $sdt->getDate("20190502");
my $dt3 = $sdt->getDate("2019年05月03日");
print $dt1->strftime("%Y-%m-%d\n");
print $dt2->strftime("%Y-%m-%d\n");
print $dt3->strftime("%Y-%m-%d\n");
|
Chain of Responsibilityパターンを使用した例 StringToDate.pm package StringToDate {
use DateTime;
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub setNext {
my ($this, $next) = @_;
$this->{next} = $next;
return $next;
}
sub toDate {
my ($this, $str) = @_;
my $dt = $this->resolve($str);
if (defined $dt) {
return $dt;
}
elsif (defined $this->{next}) {
return $this->{next}->toDate($str);
}
else {
return undef;
}
}
sub resolve {
console.log("resolve メソッドを定義してください。");
}
}
1;
SlashDelimitDate.pm package SlashDelimitDate
use base qw(StringToDate);
use DateTime;
sub resolve {
my ($this, $str) = @_;
if (length $str == 10) {
# yyyy/MM/dd
my $y = 0 + substr($str, 0, 4);
my $m = 0 + substr($str, 5, 2);
my $d = 0 + substr($str, 8, 2);
return new DateTime( year=>$y, month=>$m, day=>$d );
}
else {
return undef;
}
}
}
1;
NonDelimitDate.pm package NonDelimitDate
use base qw(StringToDate);
use DateTime;
sub resolve {
my ($this, $str) = @_;
if (length $str == 8) {
# yyyyMMdd
my $y = 0 + substr(str, 0, 4);
my $m = 0 + substr(str, 4, 2);
my $d = 0 + substr(str, 6, 2);
return new DateTime( year=>$y, month=>$m, day=>$d );
}
else {
return undef;
}
}
}
1;
KanjiDelimitDate.pm package KanjiDelimitDate
use base qw(StringToDate);
use DateTime;
sub resolve(str) {
my ($this, $str) = @_;
if (length $str == 17) {
# yyyy年mm月dd日
my $y = 0 + substr(str, 0, 4);
my $m = 0 + substr(str, 7, 2);
my $d = 0 + substr(str, 12, 2);
return new DateTime( year=>$y, month=>$m, day=>$d );
}
else {
return undef;
}
}
}
1;
Main.pl use lib qw(./);
use SlashDelimitDate;
use NonDelimitDate;
use KanjiDelimitDate;
my $sdt = new SlashDelimitDate();
my $ndt = new NonDelimitDate();
my $kdt = new KanjiDelimitDate();
$sdt->setNext($ndt)->setNext($kdt);
my $dt1 = $sdt->toDate("2019/05/01");
my $dt2 = $sdt->toDate("20190502");
my $dt3 = $sdt->toDate("2019年05月03日");
print $dt1->strftime("%Y-%m-%d\n");
print $dt2->strftime("%Y-%m-%d\n");
print $dt3->strftime("%Y-%m-%d\n");
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.rb require 'date'
class StringToDate
getDate(str)
if str.size == 10 then
# yyyy/MM/dd
y = str.slice(0..3).to_i
m = str.slice(5..6).to_i
d = str.slice(8..9).to_i
return Date.new(y, m, d)
elsif str.size == 8 then
# yyyyMMdd
y = str.slice(0..3).to_i
m = str.slice(4..5).to_i
d = str.slice(6..7).to_i
return Date.new(y, m, d)
}
elsif str.size == 11 then
# yyyy年mm月dd日
y = str.slice(0..3).to_i
m = str.slice(5..6).to_i
d = str.slice(8..9).to_i
return Date.new(y, m, d)
end
return nil
end
end
Main.rb require './StringToDate'
sdt = StringToDate.new();
dt1 = sdt.getDate("2019/05/01")
dt2 = sdt.getDate("20190502")
dt3 = sdt.getDate("2019年05月03日")
puts dt1.strftime("%Y-%m-%d")
puts dt2.strftime("%Y-%m-%d")
puts dt3.strftime("%Y-%m-%d")
|
Chain of Responsibilityパターンを使用した例 StringToDate.rb require 'date'
class StringToDate
def setNext(nxt)
@next = nxt
return nxt
end
def toDate(str)
dt = resolve(str)
if dt != nil then
return dt
elsif (@next != nil then
return @next.toDate(str)
else
return nil
end
end
def resolve(str)
puts "resolve メソッドを定義してください。"
end
end
SlashDelimitDate.rb require './StringToDate'
class SlashDelimitDate < StringToDate
def resolve(str) {
if str.size == 10 then
# yyyy/MM/dd
y = str.slice(0..3).to_i
m = str.slice(5..6).to_i
d = str.slice(8..9).to_i
return Date.new(y, m, d)
else
return nil
end
end
end
NonDelimitDate.rb require './StringToDate'
class NonDelimitDate < StringToDate
def resolve(str)
if str.size == 8 then
# yyyyMMdd
y = str.slice(0..3).to_i
m = str.slice(4..5).to_i
d = str.slice(6..7).to_i
return Date.new(y, m, d)
else
return nil
end
end
end
KanjiDelimitDate.rb require './StringToDate'
class KanjiDelimitDate < StringToDate
def resolve(str)
if str.size == 11 then
# yyyy年mm月dd日
y = str.slice(0..3).to_i
m = str.slice(5..6).to_i
d = str.slice(8..9).to_i
return Date.new(y, m, d)
else
return nil
end
end
end
Main.rb require './SlashDelimitDate'
require './NonDelimitDate'
require './KanjiDelimitDate'
sdt = SlashDelimitDate.new()
ndt = NonDelimitDate.new()
kdt = KanjiDelimitDate.new()
sdt.setNext(ndt).setNext(kdt)
dt1 = sdt.toDate("2019/05/01")
dt2 = sdt.toDate("20190502")
dt3 = sdt.toDate("2019年05月03日")
puts dt1.strftime("%Y-%m-%d")
puts dt2.strftime("%Y-%m-%d")
puts dt3.strftime("%Y-%m-%d")
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.py import datetime
class StringToDate:
def getDate(self, str):
if len(str) == 10:
# yyyy/MM/dd
y = int(str[0:4])
m = int(str[5:7])
d = int(str[8:10])
return datetime.date(y, m, d)
elif len(str) == 8:
# yyyyMMdd
y = int(str[0:4])
m = int(str[4:6])
d = int(str[6:8])
return datetime.date(y, m, d)
elif len(str) == 11:
# yyyy年mm月dd日
y = int(str[0:4])
m = int(str[5:7])
d = int(str[8:10])
return datetime.date(y, m, d)
return None Main.py import datetime
from StringToDate import StringToDate
sdt = StringToDate()
dt1 = sdt.getDate("2019/05/01")
dt2 = sdt.getDate("20190502")
dt3 = sdt.getDate("2019年05月03日")
print(dt1.strftime("%Y-%m-%d"))
print(dt2.strftime("%Y-%m-%d"))
print(dt3.strftime("%Y-%m-%d"))
|
Chain of Responsibilityパターンを使用した例 StringToDate.py from abc import ABCMeta, abstractmethod
class StringToDate(metaclass=ABCMeta):
def setNext(self, next):
self.next = next
return next
def toDate(self, str):
dt = self.resolve(str)
if dt != None:
return dt
elif self.next != None:
return self.next.toDate(str)
else:
return None
@abstractmethod
def resolve(self, str):
pass
SlashDelimitDate.py import datetime
from StringToDate import StringToDate
class SlashDelimitDate(StringToDate):
def resolve(self, str):
if len(str) == 10:
# yyyy/MM/dd
y = int(str[0:4])
m = int(str[5:7])
d = int(str[8:10])
return datetime.date(y, m, d)
else:
return None
NonDelimitDate.py import datetime
from StringToDate import StringToDate
class NonDelimitDate(StringToDate):
def resolve(self, str):
if len(str) == 8:
# yyyyMMdd
y = int(str[0:4])
m = int(str[4:6])
d = int(str[6:8])
return datetime.date(y, m, d)
else:
return None
KanjiDelimitDate.py import datetime
from StringToDate import StringToDate
class KanjiDelimitDate(StringToDate):
def resolve(self, str):
if len(str) == 11:
# yyyy年mm月dd日
y = int(str[0:4])
m = int(str[5:7])
d = int(str[8:10])
return datetime.date(y, m, d)
else:
return None Main.py import datetime
from SlashDelimitDate import SlashDelimitDate
from NonDelimitDate import NonDelimitDate
from KanjiDelimitDate import KanjiDelimitDate
sdt = SlashDelimitDate()
ndt = NonDelimitDate()
kdt = KanjiDelimitDate()
sdt.setNext(ndt).setNext(kdt)
dt1 = sdt.toDate("2019/05/01")
dt2 = sdt.toDate("20190502")
dt3 = sdt.toDate("2019年05月03日")
print(dt1.strftime("%Y-%m-%d"))
print(dt2.strftime("%Y-%m-%d"))
print(dt3.strftime("%Y-%m-%d"))
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.php <?php
class StringToDate {
public function getDate($str) {
$dt = new DateTime();
if (strlen($str) == 10) {
// yyyy/MM/dd
$y = (int)substr($str, 0, 4);
$m = (int)substr($str, 5, 2);
$d = (int)substr($str, 8);
$dt->setDate($y, $m, $d);
return $dt;
}
else if (strlen($str) == 8) {
// yyyyMMdd
$y = (int)substr($str, 0, 4);
$m = (int)substr($str, 4, 2);
$d = (int)substr($str, 6);
$dt->setDate($y, $m, $d);
return $dt;
}
else if (strlen($str) == 17) {
// yyyy年mm月dd日
$y = (int)substr($str, 0, 4);
$m = (int)substr($str, 7, 2);
$d = (int)substr($str, 12, 2);
$dt->setDate($y, $m, $d);
return $dt;
}
return null;
}
}
?>
Main.php <?php
StringToDate $sdt = new StringToDate();
$dt1 = $sdt->getDate("2019/05/01");
$dt2 = $sdt->getDate("20190502");
$dt3 = $sdt->getDate("2019年05月03日");
print $dt1->format("Y-m-d") . "\n";
print $dt2->format("Y-m-d") . "\n";
print $dt3->format("Y-m-d") . "\n";
?>
|
Chain of Responsibilityパターンを使用した例 StringToDate.php <?php
abstract class StringToDate {
public function setNext($next) {
$this->next = $next;
return $next;
}
public function toDate(String $str) {
$dt = $this->resolve($str);
if ($dt != null) {
return $dt;
}
else if ($this->next != null) {
return $this->next->toDate($str);
}
else {
return null;
}
}
protected abstract function resolve(String $str);
}
?>
SlashDelimitDate.php <?php
require_once('StringToDate.php');
class SlashDelimitDate extends StringToDate {
protected function resolve($str) {
if (strlen($str) == 10) {
// yyyy/MM/dd
$y = (int)substr($str, 0, 4);
$m = (int)substr($str, 5, 2);
$d = (int)substr($str, 8);
$dt = new DateTime();
$dt->setDate($y, $m, $d);
return $dt;
}
else {
return null;
}
}
}
?>
NonDelimitDate.php <?php
require_once('StringToDate.php');
class NonDelimitDate extends StringToDate {
protected function resolve(String $str) {
if (strlen($str) == 8) {
// yyyy/MM/dd
$y = (int)substr($str, 0, 4);
$m = (int)substr($str, 4, 2);
$d = (int)substr($str, 6);
$dt = new DateTime();
$dt->setDate($y, $m, $d);
return $dt;
}
else {
return null;
}
}
}
?>
KanjiDelimitDate.php <?php
require_once('StringToDate.php');
class KanjiDelimitDate extends StringToDate {
protected function resolve(String $str) {
if (strlen($str) == 17) {
// yyyy/MM/dd
$y = (int)substr($str, 0, 4);
$m = (int)substr($str, 7, 2);
$d = (int)substr($str, 12);
$dt = new DateTime();
$dt->setDate($y, $m, $d);
return $dt;
}
else {
return null;
}
}
}
?>
Main.java <?php
require_once('SlashDelimitDate.php');
require_once('NonDelimitDate.php');
require_once('KanjiDelimitDate.php');
$sdt = new SlashDelimitDate();
$ndt = new NonDelimitDate();
$kdt = new KanjiDelimitDate();
$sdt->setNext($ndt)->setNext($kdt);
$dt1 = $sdt->toDate("2019/05/01");
$dt2 = $sdt->toDate("20190502");
$dt3 = $sdt->toDate("2019年05月03日");
print $dt1->format("Y-m-d") . "\n";
print $dt2->format("Y-m-d") . "\n";
print $dt3->format("Y-m-d") . "\n";
?>
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.ts export
class StringToDate {
public getDate(str:string):Date {
if (str.length == 10) {
// yyyy/MM/dd
let y:number = Number.parseInt(str.substring(0, 4));
let m:number = Number.parseInt(str.substring(5, 7));
let d:number = Number.parseInt(str.substring(8));
return new Date(y, m - 1, d);
}
else if (str.length == 8) {
// yyyyMMdd
let y:number = Number.parseInt(str.substring(0, 4));
let m:number = Number.parseInt(str.substring(4, 6));
let d:number = Number.parseInt(str.substring(6));
return new Date(y, m - 1, d);
}
else if (str.length == 11) {
// yyyy年mm月dd日
let y:number = Number.parseInt(str.substring(0, 4));
let m:number = Number.parseInt(str.substring(5, 7));
let d:number = Number.parseInt(str.substring(8, 10));
return new Date(y, m - 1, d);
}
return null;
}
}
Main.ts import {StringToDate} from "./StringToDate";
function toString(dt:Date) {
return (dt.getFullYear()) + "-"
+ ('0' + (dt.getMonth() + 1)).slice(-2) + "-"
+ ('0' + dt.getDate()).slice(-2);
}
let sdt:StringToDate = new StringToDate();
let dt1:Date = sdt.getDate("2019/05/01");
let dt2:Date = sdt.getDate("20190502");
let dt3:Date = sdt.getDate("2019年05月03日");
process.stdout.write(toString(dt1));
process.stdout.write(toString(dt2));
process.stdout.write(toString(dt3));
|
Chain of Responsibilityパターンを使用した例 StringToDate.ts export
abstract class StringToDate {
private next:StringToDate;
public setNext(next:StringToDate):StringToDate {
this.next = next;
return next;
}
public toDate(str:string):Date {
let dt:Date = this.resolve(str);
if (dt != null) {
return dt;
}
else if (this.next != null) {
return this.next.toDate(str);
}
else {
return null;
}
}
public abstract resolve(str:string):Date;
}
SlashDelimitDate.ts import {StringToDate} from "./StringToDate";
export
class SlashDelimitDate extends StringToDate {
public resolve(str:string):Date {
if (str.length == 10) {
// yyyy/MM/dd
let y:number = Number.parseInt(str.substring(0, 4));
let m:number = Number.parseInt(str.substring(5, 7));
let d:number = Number.parseInt(str.substring(8));
return new Date(y, m - 1, d);
}
else {
return null;
}
}
}
NonDelimitDate.ts import {StringToDate} from "./StringToDate";
export
class NonDelimitDate extends StringToDate {
public resolve(str:string):Date {
if (str.length == 8) {
// yyyyMMdd
let y:number = Number.parseInt(str.substring(0, 4));
let m:number = Number.parseInt(str.substring(4, 6));
let d:number = Number.parseInt(str.substring(6));
return new Date(y, m - 1, d);
}
else {
return null;
}
}
}
KanjiDelimitDate.ts import {StringToDate} from "./StringToDate";
export
class KanjiDelimitDate extends StringToDate {
public resolve(str:string):Date {
if (str.length == 11) {
// yyyy年mm月dd日
let y:number = Number.parseInt(str.substring(0, 4));
let m:number = Number.parseInt(str.substring(5, 7));
let d:number = Number.parseInt(str.substring(8, 10));
return new Date(y, m - 1, d);
}
else {
return null;
}
}
}
Main.ts import {SlashDelimitDate} from "./SlashDelimitDate";
import {NonDelimitDate} from "./NonDelimitDate";
import {KanjiDelimitDate} from "./KanjiDelimitDate";
function toString(dt:Date) {
return (dt.getFullYear()) + "-"
+ ('0' + (dt.getMonth() + 1)).slice(-2) + "-"
+ ('0' + dt.getDate()).slice(-2);
}
let sdt:SlashDelimitDate = new SlashDelimitDate();
let ndt:NonDelimitDate = new NonDelimitDate();
let kdt:KanjiDelimitDate = new KanjiDelimitDate();
sdt.setNext(ndt).setNext(kdt);
let dt1:Date = sdt.toDate("2019/05/01");
let dt2:Date = sdt.toDate("20190502");
let dt3:Date = sdt.toDate("2019年05月03日");
process.stdout.write(toString(dt1) + "\n");
process.stdout.write(toString(dt2) + "\n");
process.stdout.write(toString(dt3) + "\n");
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.swift import Foundation
public class StringToDate {
public func getDate(_ str:String) -> Date! {
let formatter = DateFormatter()
if str.count == 10 {
// yyyy/MM/dd
formatter.dateFormat = "yyyy/MM/dd"
formatter.locale = Locale(identifier: "ja_JP")
return formatter.date(from: str)
}
else if str.count == 8 {
// yyyyMMdd
formatter.dateFormat = "yyyyMMdd"
formatter.locale = Locale(identifier: "ja_JP")
return formatter.date(from: str)
}
else if str.count == 11 {
// yyyy年mm月dd日
formatter.dateFormat = "yyyy年MM月dd日"
formatter.locale = Locale(identifier: "ja_JP")
return formatter.date(from: str)
}
return nil
}
}
Main.swift import Foundation
let sdt:StringToDate = StringToDate()
let dt1:Date! = sdt.getDate("2019/05/01")
let dt2:Date! = sdt.getDate("20190502")
let dt3:Date! = sdt.getDate("2019年05月03日")
let formatter = DateFormatter()
formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyyy-MM-dd", options: 0,
locale: Locale(identifier: "ja_JP"))
print(formatter.string(from: dt1))
print(formatter.string(from: dt2))
print(formatter.string(from: dt3))
|
Chain of Responsibilityパターンを使用した例 StringToDate.swift import Foundation
public class StringToDate {
private var next:StringToDate! = nil
@discardableResult
public func setNext(_ next:StringToDate) -> StringToDate {
self.next = next
return next
}
public func toDate(_ str:string) -> Date? {
let dt:Date? = resolve(str)
if dt != nil {
return dt
}
else if next != nil {
return next.toDate(str)
}
else {
return nil
}
}
public func resolve(_ str:String) -> Date? {
fatalError("resolve メソッドを定義してください。")
}
}
SlashDelimitDate.swift import Foundation
public class SlashDelimitDate : StringToDate {
public override func resolve(_ str:String) -> Date? {
if str.count == 10 {
// yyyy/MM/dd
let formatter = DateFormatter()
formatter.dateFormat = "yyyy/MM/dd"
formatter.locale = Locale(identifier: "ja_JP")
return formatter.date(from: str)
}
else {
return nil
}
}
}
NonDelimitDate.swift import Foundation
public class NonDelimitDate : StringToDate {
public override func resolve(_ str:String) -> Date? {
if str.count == 8 {
// yyyyMMdd
let formatter = DateFormatter()
formatter.dateFormat = "yyyyMMdd"
formatter.locale = Locale(identifier: "ja_JP")
return formatter.date(from: str)
}
else {
return nil
}
}
}
KanjiDelimitDate.swift import Foundation
public class KanjiDelimitDate : StringToDate {
public override func resolve(_ str:string) -> Date? {
if str.count == 11 {
// yyyy年mm月dd日
let formatter = DateFormatter()
formatter.dateFormat = "yyyy年MM月dd日"
formatter.locale = Locale(identifier: "ja_JP")
return formatter.date(from: str)
}
else {
return nil
}
}
}
Main.swift import Foundation
let sdt:SlashDelimitDate = SlashDelimitDate()
let ndt:NonDelimitDate = NonDelimitDate()
let kdt:KanjiDelimitDate = KanjiDelimitDate()
sdt.setNext(ndt).setNext(kdt)
let dt1:Date! = sdt.toDate("2019/05/01")
let dt2:Date! = sdt.toDate("20190502")
let dt3:Date! = sdt.toDate("2019年05月03日")
let formatter = DateFormatter()
formatter.dateFormat = DateFormatter.dateFormat(fromTemplate: "yyyy-MM-dd", options: 0,
locale: Locale(identifier: "ja_JP"))
print(formatter.string(from: dt1))
print(formatter.string(from: dt2))
print(formatter.string(from: dt3))
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.kt import java.util.*
class StringToDate {
public fun getDate(str: String):Date? {
if (str.length == 10) {
// yyyy/MM/dd
val y: Int = str.substring(0, 4).toInt()
val m: Int = str.substring(5, 7).toInt()
val d: Int = str.substring(8).toInt()
val cal: Calendar = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.time
}
else if (str.length == 8) {
// yyyyMMdd
val y: Int = str.substring(0, 4).toInt()
val m: Int = str.substring(4, 6).toInt()
val d: Int = str.substring(6).toInt()
val cal: Calendar = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.time
}
else if (str.length == 11) {
// yyyy年mm月dd日
val y: Int = str.substring(0, 4).toInt()
val m: Int = str.substring(5, 7).toInt()
val d: Int = str.substring(8, 10).toInt()
val cal: Calendar = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.time
}
return null
}
}
Main.kt import java.text.SimpleDateFormat
fun main() {
val df = SimpleDateFormat("yyyy-MM-dd")
val sdt = StringToDate()
val dt1 = sdt.getDate("2019/05/01")
val dt2 = sdt.getDate("20190502")
val dt3 = sdt.getDate("2019年05月03日")
println(df.format(dt1))
println(df.format(dt2))
println(df.format(dt3))
}
|
Chain of Responsibilityパターンを使用した例 StringToDate.kt import java.util.*
abstract class StringToDate {
private var next: StringToDate? = null
fun setNext(next: StringToDate): StringToDate {
this.next = next
return next
}
fun toDate(str: String) : Date? {
val dt: Date? = resolve(str)
return if (dt != null) {
dt
}
else if (next != null) {
next!!.toDate(str)
}
else {
null
}
}
internal abstract fun resolve(str: String) : Date?
}
SlashDelimitDate.kt import java.util.*
class SlashDelimitDate : StringToDate() {
override fun resolve(str: String) : Date? {
return if (str.length == 10) {
// yyyy/MM/dd
val y = str.substring(0, 4).toInt()
val m = str.substring(5, 7).toInt()
val d = str.substring(8).toInt()
val cal = Calendar.getInstance()
cal[y, m - 1, d, 0, 0] = 0
cal.time
}
else {
null
}
}
}
NonDelimitDate.kt import java.util.*
class NonDelimitDate : StringToDate {
override fun resolve(str: String) : Date? {
return if (str.length == 8) {
// yyyyMMdd
var y = str.substring(0, 4).toInt()
var m = str.substring(4, 6).toInt()
var d = str.substring(6).toInt()
val cal = Calendar.getInstance()
cal[y, m - 1, d, 0, 0] = 0
cal.time
}
else {
return null
}
}
}
KanjiDelimitDate.kt import java.util.*
class KanjiDelimitDate : StringToDate {
override fun resolve(str: String) : Date? {
return if (str.length == 11) {
// yyyy年mm月dd日
var y = str.substring(0, 4).toInt()
var m = str.substring(5, 7).toInt()
var d = str.substring(8, 10).toInt()
val cal = Calendar.getInstance()
cal[y, m - 1, d, 0, 0] = 0
cal.time
}
else {
return null
}
}
}
Main.kt import java.text.SimpleDateFormat
fun main() {
val sdt = SlashDelimitDate()
val ndt = NonDelimitDate()
val kdt = KanjiDelimitDate()
sdt.setNext(ndt).setNext(kdt)
val dt1 = sdt.toDate("2019/05/01")
val dt2 = sdt.toDate("20190502")
val dt3 = sdt.toDate("2019年05月03日")
println(dt.format(dt1))
println(dt.format(dt2))
println(dt.format(dt3))
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.scala import java.util.Calendar
import java.util.Date
class StringToDate {
def getDate(str: String) : Date =
if (str.length == 10) {
// yyyy/MM/dd
val y = str.substring(0, 4).toInt()
val m = str.substring(5, 7).toInt()
val d = str.substring(8).toInt()
val cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
cal.getTime()
}
else if (str.length == 8) {
// yyyyMMdd
val y: Int = str.substring(0, 4).toInt()
val m: Int = str.substring(4, 6).toInt()
val d: Int = str.substring(6).toInt()
val cal: Calendar = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
cal.getTime()
}
else if (str.length == 11) {
// yyyy年mm月dd日
val y: Int = str.substring(0, 4).toInt()
val m: Int = str.substring(5, 7).toInt()
val d: Int = str.substring(8, 10).toInt()
val cal: Calendar = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
cal.getTime()
}
else null
}
Main.scala import java.text.SimpleDateFormat
import java.util.Date
object Main {
def main(args: Array[String]) {
val df = new SimpleDateFormat("yyyy-MM-dd")
val sdt = new StringToDate()
val dt1: Date = sdt.getDate("2019/05/01")
val dt2: Date = sdt.getDate("20190502")
val dt3: Date = sdt.getDate("2019年05月03日")
System.out.println(df.format(dt1))
System.out.println(df.format(dt2))
System.out.println(df.format(dt3))
}
}
|
Chain of Responsibilityパターンを使用した例 StringToDate.scala import java.util.Date
abstract class StringToDate {
private var next: StringToDate = null
def setNext(next: StringToDate): StringToDate = {
this.next = next
next
}
def toDate(str: String) : Date = {
val dt: Date = resolve(str)
if (dt != null) dt
else if (next != null) next.toDate(str)
else null
}
abstract def resolve(str: String) : Date
}
SlashDelimitDate.scala import java.util.Calendar
import java.util.Date
class SlashDelimitDate extends StringToDate() {
protected def resolve(str: String) : Date =
if (str.length == 10) {
// yyyy/MM/dd
val y = str.substring(0, 4).toInt()
val m = str.substring(5, 7).toInt()
val d = str.substring(8).toInt()
val cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0)
cal.getTime()
}
else null
}
NonDelimitDate.scala import java.util.Calendar
import java.util.Date
class NonDelimitDate extends StringToDate {
protected def resolve(str: String) : Date =
if (str.length == 8) {
// yyyyMMdd
var y = str.substring(0, 4).toInt()
var m = str.substring(4, 6).toInt()
var d = str.substring(6).toInt()
val cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0)
cal.getTime()
}
else null
}
KanjiDelimitDate.scala import java.util.Calendar
import java.util.Date
class KanjiDelimitDate extends StringToDate {
protected def resolve(str: String) : Date =
if (str.length == 11) {
// yyyy年mm月dd日
var y = str.substring(0, 4).toInt()
var m = str.substring(5, 7).toInt()
var d = str.substring(8, 10).toInt()
val cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0)
cal.getTime()
}
else null
}
Main.scala import java.text.SimpleDateFormat
import java.util.Date
object Main {
def main(args: Array[String]) {
val sdt = new SlashDelimitDate()
val ndt = new NonDelimitDate()
val kdt = new KanjiDelimitDate()
sdt.setNext(ndt).setNext(kdt)
val dt1: Date = sdt.toDate("2019/05/01")
val dt2: Date = sdt.toDate("20190502")
val dt3: Date = sdt.toDate("2019年05月03日")
System.out.println(dt.format(dt1))
System.out.println(dt.format(dt2))
System.out.println(dt.format(dt3))
}
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.groovy class StringToDate {
Date getDate(String str) {
if (str.length() == 10) {
// yyyy/MM/dd
int y = Integer.parseInt(str.substring(0, 4))
int m = Integer.parseInt(str.substring(5, 7))
int d = Integer.parseInt(str.substring(8))
Calendar cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.getTime()
}
else if (str.length() == 8) {
// yyyyMMdd
int y = Integer.parseInt(str.substring(0, 4))
int m = Integer.parseInt(str.substring(4, 6))
int d = Integer.parseInt(str.substring(6))
Calendar cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.getTime()
}
else if (str.length() == 11) {
// yyyy年mm月dd日
int y = Integer.parseInt(str.substring(0, 4))
int m = Integer.parseInt(str.substring(5, 7))
int d = Integer.parseInt(str.substring(8, 10))
Calendar cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.getTime()
}
return null
}
}
Main.groovy class Main {
static void main(String[] args) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd")
StringToDate sdt = new StringToDate()
Date dt1 = sdt.getDate("2019/05/01")
Date dt2 = sdt.getDate("20190502")
Date dt3 = sdt.getDate("2019年05月03日")
System.out.println(df.format(dt1))
System.out.println(df.format(dt2))
System.out.println(df.format(dt3))
}
}
|
Chain of Responsibilityパターンを使用した例 StringToDate.groovy abstract class StringToDate {
private StringToDate next = null
StringToDate setNext(StringToDate next) {
this.next = next
return next
}
Date toDate(String str) {
Date dt = resolve(str)
if (dt != null) {
return dt
}
else if (next != null) {
return next.toDate(str)
}
else {
return null
}
}
abstract Date resolve(String str)
}
SlashDelimitDate.groovy class SlashDelimitDate extends StringToDate {
Date resolve(String str) {
if (str.length() == 10) {
// yyyy/MM/dd
int y = Integer.parseInt(str.substring(0, 4))
int m = Integer.parseInt(str.substring(5, 7))
int d = Integer.parseInt(str.substring(8))
Calendar cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.getTime()
}
else {
return null
}
}
}
NonDelimitDate.groovy class NonDelimitDate extends StringToDate {
Date resolve(String str) {
if (str.length() == 8) {
// yyyyMMdd
int y = Integer.parseInt(str.substring(0, 4))
int m = Integer.parseInt(str.substring(4, 6))
int d = Integer.parseInt(str.substring(6))
Calendar cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.getTime()
}
else {
return null
}
}
}
KanjiDelimitDate.groovy class KanjiDelimitDate extends StringToDate {
Date resolve(String str) {
if (str.length() == 11) {
// yyyy年mm月dd日
int y = Integer.parseInt(str.substring(0, 4))
int m = Integer.parseInt(str.substring(5, 7))
int d = Integer.parseInt(str.substring(8, 10))
Calendar cal = Calendar.getInstance()
cal.set(y, m - 1, d, 0, 0, 0)
return cal.getTime()
}
else {
return null
}
}
}
Main.groovy class Main {
static void main(String[] args) {
SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd")
SlashDelimitDate sdt = new SlashDelimitDate()
NonDelimitDate ndt = new NonDelimitDate()
KanjiDelimitDate kdt = new KanjiDelimitDate()
sdt.setNext(ndt).setNext(kdt)
Date dt1 = sdt.toDate("2019/05/01")
Date dt2 = sdt.toDate("20190502")
Date dt3 = sdt.toDate("2019年05月03日")
System.out.println(df.format(dt1))
System.out.println(df.format(dt2))
System.out.println(df.format(dt3))
}
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 StringToDate.go import (
"strconv"
"time"
)
type StringToDate struct {}
func (self *StringToDate) GetDate(str string) (time.Time, bool) {
if len(str) == 10 {
// yyyy/MM/dd
var y, _ = strconv.Atoi(str[:4])
var m, _ = strconv.Atoi(str[5:7])
var d, _ = strconv.Atoi(str[8:])
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local), true
} else if len(str) == 8 {
// yyyyMMdd
var y, _ = strconv.Atoi(str[:4])
var m, _ = strconv.Atoi(str[5:6])
var d, _ = strconv.Atoi(str[7:])
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local), true
} else if len(str) == 17 {
// yyyy年mm月dd日
var y, _ = strconv.Atoi(str[:4])
var m, _ = strconv.Atoi(str[7:9])
var d, _ = strconv.Atoi(str[12:14])
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local), true
}
return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local), false
}
Main.go import "fmt"
func main() {
const layout = "2006-01-02"
var sdt = new(StringToDate)
var dt1, _ = sdt.GetDate("2019/05/01")
var dt2, _ = sdt.GetDate("20190502")
var dt3, _ = sdt.GetDate("2019年05月03日")
fmt.Println(df1.format(layout))
fmt.Println(df2.format(layout))
fmt.Println(df3.format(layout))
}
|
Chain of Responsibilityパターンを使用した例 StringToDate.go import (
"errors"
"time"
)
type IDate interface {
SetNext(IDate) IDate
Resolve(string) (time.Time, bool)
ToDate(IDate, string) (time.Time, bool)
}
type StringToDate struct {
IDate
next IDate
}
func (self *StringToDate) SetNext(next *IDate) IDate {
self.next = next
return next
}
func (self *StringToDate) ToDate(toDate IDate, str string) (time.Time, bool) {
var dt, ok = toDate.Resolve(str)
if ok == true {
return dt, true
} else if self.next != nil {
return self.next.ToDate(self.next, str)
} else {
return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local), false
}
}
func (self *StringToDate) Resolve(str string) (time.Time, bool) {
panic(errors.New("Resolve メソッドを定義してください。"))
return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local), false
}
SlashDelimitDate.go import (
"strconv"
"time"
)
type SlashDelimitDate struct {
*StringToDate
}
func (self *SlashDelimitDate) Resolve(str string) (time.Time, bool) {
if len(str) == 10 {
// yyyy/MM/dd
var y, _ = strconv.Atoi(str[:4])
var m, _ = strconv.Atoi(str[5:7])
var d, _ = strconv.Atoi(str[8:])
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local), true
}
return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local), false
}
func NewSlashDelimitDate() *SlashDelimitDate {
return &SlashDelimitDate {
&StringToDate{},
}
}
NonDelimitDate.go import (
"strconv"
"time"
)
type NonDelimitDate struct {
*StringToDate
}
func (self *SlashDelimitDate) Resolve(str string) (time.Time, bool) {
if len(str) == 8 {
// yyyyMMdd
var y, _ = strconv.Atoi(str[:4])
var m, _ = strconv.Atoi(str[5:6])
var d, _ = strconv.Atoi(str[7:])
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local), true
}
return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local), false
}
func NewNonDelimitDate() *NonDelimitDate {
return &NonDelimitDate {
&StringToDate{},
}
}
KanjiDelimitDate.go import (
"strconv"
"time"
)
type KanjiDelimitDate struct {
*StringToDate
}
func (self *SlashDelimitDate) Resolve(str string) (time.Time, bool) {
if len(str) == 17 {
// yyyy年mm月dd日
var y, _ = strconv.Atoi(str[:4])
var m, _ = strconv.Atoi(str[7:9])
var d, _ = strconv.Atoi(str[12:14])
return time.Date(y, time.Month(m), d, 0, 0, 0, 0, time.Local), true
}
return time.Date(0, 0, 0, 0, 0, 0, 0, time.Local), false
}
func NewKanjiDelimitDate() *KanjiDelimitDate {
return &KanjiDelimitDate {
&StringToDate{},
}
}
Main.go import "fmt"
func main() {
const layout = "2006-01-02"
var sdt = NewSlashDelimitDate()
var ndt = NewNonDelimitDate()
var kdt = NewKanjiDelimitDate()
sdt.SetNext(ndt).SetNext(kdt)
var dt1, _ = sdt.ToDate("2019/05/01")
var dt2, _ = sdt.ToDate("20190502")
var dt3, _ = sdt.ToDate("2019年05月03日")
fmt.Println(df1.format(layout))
fmt.Println(df2.format(layout))
fmt.Println(df3.format(layout))
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの Next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの ToDate メソッドを呼び出して日付型に変換しています。 ToDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |
|
Chain of Responsibilityパターンを使用しない例 stringtodate.d import std.conv;
import std.datetime;
public class StringToDate {
public DateTime* getDate(in string str) {
if (str.length == 10) {
// yyyy/MM/dd
int y = to!(int)(str[0..4]);
int m = to!(int)(str[5..7]);
int d = to!(int)(str[8..10]);
return new DateTime(y, m, d, 0, 0, 0);
}
else if (str.length == 8) {
// yyyyMMdd
int y = to!(int)(str[0..4]);
int m = to!(int)(str[4..6]);
int d = to!(int)(str[6..8]);
return new DateTime(y, m, d, 0, 0, 0);
}
else if (str.length == 17) {
// yyyy年mm月dd日
int y = to!(int)(str[0..4]);
int m = to!(int)(str[7..9]);
int d = to!(int)(str[12..14]);
return new DateTime(y, m, d, 0, 0, 0);
}
return null;
}
}
main.d import std.stdio;
import std.datetime;
import stringtodate;
public int main() {
StringToDate sdt = new StringToDate();
DateTime* dt1 = sdt.getDate("2019/05/01");
DateTime* dt2 = sdt.getDate("20190502");
DateTime* dt3 = sdt.getDate("2019年05月03日");
writefln("%04d-%02d-%02d", dt1.year, dt1.month, dt1.day);
writefln("%04d-%02d-%02d", dt2.year, dt2.month, dt2.day);
writefln("%04d-%02d-%02d", dt3.year, dt3.month, dt3.day);
return 0;
}
|
Chain of Responsibilityパターンを使用した例 stringtodate.d import std.datetime;
public abstract class StringToDate {
private StringToDate next = null;
public StringToDate setNext(StringToDate next) {
this.next = next;
return next;
}
public DateTime* toDate(in string str) {
DateTime* dt = resolve(str);
if (dt !is null) {
return dt;
}
else if (next !is null) {
return next.toDate(str);
}
else {
return null;
}
}
protected abstract DateTime* resolve(in string str);
}
slashdelimitdate.d import stringtodate;
import std.conv;
import std.datetime;
public class SlashDelimitDate : StringToDate {
protected override DateTime* resolve(in string str) {
if (str.length == 10) {
// yyyy/MM/dd
int y = to!(int)(str[0..4]);
int m = to!(int)(str[5..7]);
int d = to!(int)(str[8..10]);
return new DateTime(y, m, d, 0, 0, 0);
}
else {
return null;
}
}
}
nondelimitdate.d import stringtodate;
import std.conv;
import std.datetime;
public class NonDelimitDate : StringToDate {
protected override DateTime* resolve(in string str) {
if (str.length == 8) {
// yyyyMMdd
int y = to!(int)(str[0..4]);
int m = to!(int)(str[4..6]);
int d = to!(int)(str[6..8]);
return new DateTime(y, m, d, 0, 0, 0);
}
else {
return null;
}
}
}
kanjidelimitdate.d import stringtodate;
import std.conv;
import std.datetime;
public class KanjiDelimitDate : StringToDate {
protected override DateTime* resolve(in string str) {
if (str.length() == 17) {
// yyyy年mm月dd日
int y = to!(int)(str[0..4]);
int m = to!(int)(str[7..9]);
int d = to!(int)(str[12..14]);
return new DateTime(y, m, d, 0, 0, 0);
}
else {
return null;
}
}
}
main.d import std.stdio;
import std.datetime;
import stringtodate;
import slashdelimitdate;
import nondelimitdate;
import kanjidelimitdate;
public int main() {
SlashDelimitDate sdt = new SlashDelimitDate();
NonDelimitDate ndt = new NonDelimitDate();
KanjiDelimitDate kdt = new KanjiDelimitDate();
sdt.setNext(ndt).setNext(kdt);
DateTime* dt1 = sdt.getDate("2019/05/01");
DateTime* dt2 = sdt.getDate("20190502");
DateTime* dt3 = sdt.getDate("2019年05月03日");
writefln("%04d-%02d-%02d", dt1.year, dt1.month, dt1.day);
writefln("%04d-%02d-%02d", dt2.year, dt2.month, dt2.day);
writefln("%04d-%02d-%02d", dt3.year, dt3.month, dt3.day);
return 0;
}
|
|
日付型への変換メソッド(getDate)の中で、文字列の長さを調べることによって形式を知り、年月日を求め日付型を作成しています。 しかし、これでは新しい形式が増えたときにクラスを作り変えなければならなくなります。 |
Chain of Responsibility パターンでは、形式ごとに、StringToDate を継承したサブクラスを作成しています。 そして、それぞれのインスタンスを生成し、あるインスタンスを別のサブクラスの next に入れることによって、チェーンを作っています。 そして、チェーンの先頭となるインスタンスの toDate メソッドを呼び出して日付型に変換しています。 toDate メソッドは、次のように実行されます。
先ほども言いましたが、毎回チェーンをたどっていくため、処理速度は遅くなります。しかし、チェーンの順番を変えることにより、いろいろな状況に対応できる柔軟性が得られます。 |