Prototypeパターン
newではなく、既存のインスタンスをコピーする

prototype という単語は、日本語で「試作品」「原型」といった意味を持ちます。Prototype パターンは、あらかじめ用意しておいた「原型」からインスタンスを生成するようにするためのパターンです。
例えば、「直線を描く」機能しか持たない図形エディターを想像してみましょう。この図形エディターで星型を書きたいときには、直線を組み合わせることで、星の形を作成していくことになります。では、星型がいくつも欲しいときはどうすればよいでしょう?直線を組み合わせて星型を描くという作業を何度も繰り返す必要が出てきます。こんなとき、最初に作成した星型(直線の集まり)を「プロトタイプ」として登録しておき、これをコピーすることで星型が作成できれば、作業がとても楽になります。
Prototype パターンは、このように「プロトタイプからインスタンスを生成する」ことができるようにするためのパターンです。

Prototypeパターンを実現するには、クラスの中に自分のクローンを返すメソッド(clone)を用意しておきます。クローンとは、フィールドの値が等しいインスタンスのことです。
クローンを作るということは、オブジェクト指向プログラミングにおいてとても重要なアイディアです。フィールドの数が多いクラスの場合、すべてを引数として設定したコンストラクタを使ってインスタンスを生成したり、インスタンスを生成した後メソッドを呼んでたくさんのフィールドにいちいち値を設定していくのでは面倒です。すでに生成されているインスタンスのクローンを作る方が効率的です。クラスを作る人が思いやりを込めてcloneメソッドを用意しておいてあげれば、クラスを使う人は楽ができます。
ただし、cloneメソッドによって行われるのは、フィールドの内容をそのままコピーするという動作です。言い換えればフィールドの先にあるインスタンスの中身までは考慮しないということです。例えば、フィールドの先に配列があったとします。cloneメソッドでコピーされるのは、配列への参照のみで、配列の要素1つひとつがコピーされるわけではありません。
また、cloneは、コピーを行うだけであり、コンストラクタを呼ぶわけではありません。インスタンス生成時に何か特殊な初期処理を必要とする場合は、別途記述する必要があります。
例題
文字列を修飾して表示する MessageBox クラスを作りなさい。このクラスは、枠の文字や横幅、文字の不足する部分に埋める文字を設定した後、メッセージを表示します。
|
Prototypeパターンを使用しない例 MessageBox.java public class MessageBox {
private char decoChar = ' ';
private int width = 20;
private char padding = ' ';
private String message = "";
public MessageBox() {}
public void setChar(char c) {
decoChar = c;
}
public void setWidth(int w) {
width = w;
}
public void setPadding(char p) {
padding = p;
}
public void setMessage(String m) {
message = m;
}
public void print() {
int strLength = message.getBytes().length;
if (strLength > width) {
message = message.substring(0, width);
} else {
int pl = width - strLength;
char[] p = new char[pl];
for (int i = 0; i < pl; i++)
p[i] = padding;
message = message.concat(new String(p));
}
for (int i = 0; i < width + 4; i++) {
System.out.print(decoChar);
}
System.out.println("");
System.out.println(decoChar + " " + message + " " + decoChar);
for (int i = 0; i < width + 4; i++) {
System.out.print(decoChar);
}
System.out.println("");
}
}
Main.java public class Main {
public static void main(String[] args) {
MessageBox mbx1 = new MessageBox();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage("Hello, World");
MessageBox mbx2 = new MessageBox();
mbx2.setChar('*');
mbx2.setWidth(20);
mbx2.setPadding('.');
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
}
}
|
Prototypeパターンを使用した例 MessageBox.java public class MessageBox implements Cloneable {
private char decoChar = ' ';
private int width = 20;
private char padding = ' ';
private String message = "";
public MessageBox() {}
public void setChar(char c) {
decoChar = c;
}
public void setWidth(int w) {
width = w;
}
public void setPadding(char p) {
padding = p;
}
public void setMessage(String m) {
message = m;
}
public void print() {
int strLength = message.getBytes().length;
if (strLength > width) {
message = message.substring(0, width);
} else {
int pl = width - strLength;
char[] p = new char[pl];
for (int i = 0; i < pl; i++)
p[i] = padding;
message = message.concat(new String(p));
}
for (int i = 0; i < width + 4; i++) {
System.out.print(decoChar);
}
System.out.println("");
System.out.println(decoChar + " " + message + " " + decoChar);
for (int i = 0; i < width + 4; i++) {
System.out.print(decoChar);
}
System.out.println("");
}
public MessageBox createClone() {
MessageBox p = null;
try {
p = (MessageBox) clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return p;
}
}
Main.java public class Main {
public static void main(String[] args) {
MessageBox mbx1 = new MessageBox();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage("Hello, World");
MessageBox mbx2 = mbx1.createClone();
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
}
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、java.lang.Cloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 なお、createClone() から呼んでいる clone() は、java.lang.Object.clone() です。 |
|
Prototypeパターンを使用しない例 messageBox.h #include <string>
class MessageBox
{
private:
char decoChar;
int width;
char padding;
std::string message;
public:
MessageBox(void);
virtual ~MessageBox(void);
void setChar(char);
void setWidth(int);
void setPadding(char);
void setMessage(std::string);
void print(void);
}; messageBox.cpp #include "messageBox.h"
#include <iostream>
using namespace std;
MessageBox::MessageBox(void) : decoChar(' '),
width(20),
padding(' '),
message("") {}
MessageBox::~MessageBox(void) {}
void MessageBox::setChar(char c) {decoChar = c;}
void MessageBox::setWidth(int w) {width = w;}
void MessageBox::setPadding(char p) {padding = p;}
void MessageBox::setMessage(string m) {message = m;}
void MessageBox::print(void) {
int strLength = message.length();
if (strLength > width)
message = message.substr(0, width);
else
message.resize(width, padding);
for (int i = 0 ; i < width + 4 ; i++)
cout << decoChar;
cout << endl;
cout << decoChar << " " << message << " " << decoChar
<< endl;
for (int i = 0 ; i < width + 4 ; i++)
cout << decoChar;
cout << endl;
} Main.java #include "messageBox.h"
int main() {
MessageBox* mbx1 = new MessageBox();
MessageBox* mbx2 = new MessageBox();
mbx1->setChar('*');
mbx1->setWidth(20);
mbx1->setPadding('.');
mbx1->setMessage("Hello, World");
mbx2->setChar('*');
mbx2->setWidth(20);
mbx2->setPadding('.');
mbx2->setMessage("Ciao, Mondo");
mbx1->print();
mbx2->print();
delete mbx1;
delete mbx2;
return 0;
}
|
Prototypeパターンを使用した例 messageBox.h #include <string>
class MessageBox
{
private:
char decoChar;
int width;
char padding;
std::string message;
public:
MessageBox(void);
virtual ~MessageBox(void);
void setChar(char c);
void setWidth(int w);
void setPadding(char p);
void setMessage(std::string m);
void print(void);
MessageBox* createClone(void);
}; messageBox.cpp #include "messageBox.h"
#include <iostream>
using namespace std;
MessageBox::MessageBox(void) : decoChar(' '),
width(20),
padding(' '),
message("") {
}
MessageBox::~MessageBox(void) {}
void MessageBox::setChar(char c) {decoChar = c;}
void MessageBox::setWidth(int w) {width = w;}
void MessageBox::setPadding(char p) {padding = p;}
void MessageBox::setMessage(string m) {message = m;}
void MessageBox::print() {
int strLength = message.length();
if (strLength > width)
message = message.substr(0, width);
else
message.resize(width, padding);
for (int i = 0 ; i < width + 4 ; i++)
cout < decoChar;
cout << endl;
cout << decoChar << " " << message << " " << decoChar
<< endl;
for (int i = 0 ; i < width + 4 ; i++)
cout << decoChar;
cout << endl;
}
MessageBox* MessageBox::createClone(void) {
return new MessageBox(*this);
}
main.cpp #include "messageBox.h"
int main() {
MessageBox* mbx1 = new MessageBox();
mbx1->setChar('*');
mbx1->setWidth(20);
mbx1->setPadding('.');
mbx1->setMessage("Hello, World");
MessageBox* mbx2 = mbx1->createClone();
mbx2->setMessage("Ciao, Mondo");
mbx1->print();
mbx2->print();
delete mbx1;
delete mbx2;
return 0;
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、createClone メソッドを追加しています。そこでは、自分自身を引数に MessageBox のインスタンスを生成しています。 自分自身を引数にしたコンストラクタをコピーコンストラクタといい、自分自身の複製を作ってくれます。コピーコンストラクタは、通常、コンパイラが暗黙のうちに生成しています。しかし、暗黙のうちに生成されたデフォルトコピーコンストラクタは、単にクラスのメンバをそのままコピーするだけです。したがって、インスタンス内に動的に確保された配列などがあっても、その動的領域まではコピーしません。ポインタの内容だけをコピーします。その結果、2つのインスタンスは同じ領域を指し示すことになり、一方を変更すると他方も変更されることになります。この例では、動的に確保された領域がないので、デフォルトコピーコンストラクタで問題ありません。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.cs class MessageBox
{
private char decoChar = ' ';
private int width = 20;
private char padding = ' ';
private string message = "";
public void SetChar(char c)
{
decoChar = c;
}
public void SetWidth(int w)
{
width = w;
}
public void SetPadding(char p)
{
padding = p;
}
public void SetMessage(string m)
{
message = m;
}
public void Print()
{
int strLength = message.Length;
message = strLength > width ? message.Substring(0, width)
: message.PadRight(width, padding);
for (int i = 0; i < width + 4; i++)
{
Console.Write(decoChar);
}
Console.WriteLine("");
Console.WriteLine(decoChar + " " + message + " " + decoChar);
for (int i = 0; i < width + 4; i++)
{
Console.Write(decoChar);
}
Console.WriteLine("");
}
} Program.cs class Program
{
static void Main(string[] args)
{
MessageBox mbx1 = new MessageBox();
MessageBox mbx2 = new MessageBox();
mbx1.SetChar('*');
mbx1.SetWidth(20);
mbx1.SetPadding('.');
mbx1.SetMessage("Hello, World");
mbx2.SetChar('*');
mbx2.SetWidth(20);
mbx2.SetPadding('.');
mbx2.SetMessage("Ciao, Mondo");
mbx1.Print();
mbx2.Print();
}
}
|
Prototypeパターンを使用した例 MessageBox.cs class MessageBox : ICloneable
{
private char decoChar = ' ';
private int width = 20;
private char padding = ' ';
private string message = "";
public void SetChar(char c)
{
decoChar = c;
}
public void SetWidth(int w)
{
width = w;
}
public void SetPadding(char p)
{
padding = p;
}
public void SetMessage(string m)
{
message = m;
}
public void Print()
{
int strLength = message.Length;
message = strLength > width ? message.Substring(0, width)
: message.PadRight(width, padding);
for (int i = 0; i < width + 4; i++)
{
Console.Write(decoChar);
}
Console.WriteLine("");
Console.WriteLine(decoChar + " " + message + " " + decoChar);
for (int i = 0; i < width + 4; i++)
{
Console.Write(decoChar);
}
Console.WriteLine("");
}
public MessageBox CreateClone()
{
return (MessageBox)Clone();
}
public Object Clone()
{
return MemberwiseClone();
}
} Program.cs class Program
{
static void Main(string[] args)
{
MessageBox mbx1 = new MessageBox();
mbx1.SetChar('*');
mbx1.SetWidth(20);
mbx1.SetPadding('.');
mbx1.SetMessage("Hello, World");
MessageBox mbx2 = mbx1.CreateClone();
mbx2.SetMessage("Ciao, Mondo");
mbx1.Print();
mbx2.Print();
}
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、ICloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのクローンを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、CreateClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 CreateClone() から呼んでいる Clone() は、System.ICloneable.Clone() をインプリメントした(つまり、System.ICloneable が Clone メソッドを作るよう規定している)ものです。ただし、このメソッドの戻り値の型は Object なので、利用する側で型変換しなくてはなりません。そこで、Clone メソッドをラップして、戻り値をMessageBox 型にする ラッパーメソッドである CreateClone メソッドを作成しています。 |
|
Prototypeパターンを使用しない例 abstractDisplay.vb Public Class MessageBox
Private decoChar As Char = " "c
Private width As Integer = 20
Private padding As Char = " "c
Private message As String = ""
Public Sub New()
End Sub
Public Sub SetChar(ByVal c As Char)
decoChar = c
End Sub
Public Sub SetWidth(ByVal w As Integer)
width = w
End Sub
Public Sub SetPadding(ByVal p As Char)
padding = p
End Sub
Public Sub SetMessage(ByVal m As String)
message = m
End Sub
Public Sub Print()
Dim strLength As Integer = message.Length
If strLength > width Then
message = message.Substring(0, width)
Else
message = message.PadRight(width, padding)
End If
For i As Integer = 0 To width + 3
Console.Write(decoChar)
Next
Console.WriteLine("")
Console.WriteLine(decoChar & " " & message & " " & decoChar)
For i As Integer = 0 To width + 3
Console.Write(decoChar)
Next
Console.WriteLine("")
End Sub
End Class
Program.vb Module Main
Sub Main()
Dim mbx1 As MessageBox = New MessageBox()
Dim mbx2 As MessageBox = New MessageBox()
mbx1.SetChar("*"c)
mbx1.SetWidth(20)
mbx1.SetPadding("."c)
mbx1.SetMessage("Hello, World")
mbx2.SetChar("*"c)
mbx2.SetWidth(20)
mbx2.SetPadding("."c)
mbx2.SetMessage("Ciao, Mondo")
mbx1.Print()
mbx2.Print()
End Sub
End Module
|
Prototypeパターンを使用した例 MessageBox.vb Public Class MessageBox
Implements ICloneable
Private decoChar As Char = " "c
Private width As Integer = 20
Private padding As Char = " "c
Private message As String = ""
Public Sub New()
End Sub
Public Sub SetChar(ByVal c As Char)
decoChar = c
End Sub
Public Sub SetWidth(ByVal w As Integer)
width = w
End Sub
Public Sub SetPadding(ByVal p As Char)
padding = p
End Sub
Public Sub SetMessage(ByVal m As String)
message = m
End Sub
Public Sub Print()
Dim strLength As Integer = message.Length
If strLength > width Then
message = message.Substring(0, width)
Else
message = message.PadRight(width, padding)
End If
For i As Integer = 0 To width + 3
Console.Write(decoChar)
Next
Console.WriteLine("")
Console.WriteLine(decoChar & " " & message & " " & decoChar)
For i As Integer = 0 To width + 3
Console.Write(decoChar)
Next
Console.WriteLine("")
End Sub
Public Function CreateClone() As MessageBox
Return DirectCast(Clone(), MessageBox)
End Function
Private Function Clone() As Object Implements System.ICloneable.Clone
Return MemberwiseClone()
End Function
End Class
Program.vb Module Main
Sub Main()
Dim mbx1 As MessageBox = New MessageBox()
mbx1.SetChar("*"c)
mbx1.SetWidth(20)
mbx1.SetPadding("."c)
mbx1.SetMessage("Hello, World")
Dim mbx2 As MessageBox = mbx1.CreateClone()
mbx2.SetMessage("Ciao, Mondo")
mbx1.Print()
mbx2.Print()
End Sub
End Module
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、ICloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのクローンを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、CreateClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 CreateClone() から呼んでいる Clone() は、System.ICloneable.Clone() をインプリメントした(つまり、System.ICloneable が Clone メソッドを作るよう規定している)ものです。ただし、このメソッドの戻り値の型は Object なので、利用する側で型変換しなくてはなりません。そこで、Clone メソッドをラップして、戻り値をMessageBox 型にする ラッパーメソッドである CreateClone メソッドを作成しています。 |
|
Prototypeパターンを使用しない例 MessageBox.js module.exports = class MessageBox {
constructor() {
this.decoChar = ' ';
this.width = 20;
this.padding = ' ';
this.message = "";
}
setChar(c) {
this.decoChar = c;
}
setWidth(w) {
this.width = w;
}
setPadding(p) {
this.padding = p;
}
setMessage(m) {
this.message = m;
}
print() {
let strLength = this.message.length;
if (strLength > this.width) {
this.message = this.message.substring(0, this.width);
} else {
let pl = this.width - strLength;
this.message = this.message.concat(this.padding.repeat(pl));
}
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
process.stdout.write(this.decoChar + " " + this.message + " " + this.decoChar + "\n");
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
}
} Main.js const MessageBox = require("./MessageBox.js");
let mbx1 = new MessageBox();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage("Hello, World");
let mbx2 = new MessageBox();
mbx2.setChar('*');
mbx2.setWidth(20);
mbx2.setPadding('.');
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
|
Prototypeパターンを使用した例 MessageBox.js const Cloneable = require("./Cloneable.js");
module.exports = class MessageBox extends Cloneable {
constructor() {
super();
this.decoChar = ' ';
this.width = 20;
this.padding = ' ';
this.message = "";
}
setChar(c) {
this.decoChar = c;
}
setWidth(w) {
this.width = w;
}
setPadding(p) {
this.padding = p;
}
setMessage(m) {
this.message = m;
}
print() {
let strLength = this.message.length;
if (strLength > this.width) {
this.message = this.message.substring(0, this.width);
} else {
let pl = this.width - strLength;
this.message = this.message.concat(this.padding.repeat(pl));
}
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
process.stdout.write(this.decoChar + " " + this.message + " " + this.decoChar + "\n");
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
}
createClone() {
return super.clone();
}
static get clone_properties() {
return [ "decoChar","width","padding","message",
"setChar","setWidth","setPadding",
"setMessage","print" ];
}
} Cloneable.js class Cloneable {
clone() {
const clone = Object.create(this);
for (const prop of this.constructor.clone_properties) {
clone[prop] = this[prop];
}
return clone;
}
static get clone_properties() {
return [];
}
} Main.js const MessageBox = require("./MessageBox.js");
let mbx1 = new MessageBox();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage("Hello, World");
let mbx2 = mbx1.createClone();
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、Cloneable を継承しています。Cloneable は新たにオブジェクトを作成し、clone_properties で指定されたフィールドやメソッドをコピーしています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.pm package MessageBox {
sub new {
my ($class) = @_;
my ($this) = { decoChar => " ",
width => 20,
padding => " ",
message => ""
};
return bless $this, $class;
}
sub setChar {
my ($this, $c) = @_;
$this->{decoChar} = $c;
}
sub setWidth {
my ($this, $w) = @_;
$this->{width} = $w;
}
sub setPadding {
my ($this, $p) = @_;
$this->{padding} = $p;
}
sub setMessage {
my ($this, $m) = @_;
$this->{message} = $m;
}
sub print {
my ($this) = @_;
my strLength = length $this->{$message};
if ($strLength > $this->{width}) {
$this->{message} = substr($this->{$message}, 0, $this->{width});
} else {
my $pl = $this->{width} - $strLength;
$this->{message} .= $this->{padding} x $pl;
}
print $this->{decoChar} x ($this->{width} + 4) . "\n";
print $this->{decoChar} . " " . $this->{message} . " " . $this->{decoChar} . "\n";
print $this->{decoChar} x ($this->{width} + 4) . "\n";
}
}
1;
Main.pl use lib qw(./);
use MessageBox;
my $mbx1 = new MessageBox();
$mbx1->setChar('*');
$mbx1->setWidth(20);
$mbx1->setPadding('.');
$mbx1->setMessage("Hello, World");
my $mbx2 = new MessageBox();
mbx2.setChar('*');
$mbx2->setWidth(20);
$mbx2->setPadding('.');
$mbx2->setMessage("Ciao, Mondo");
$mbx1->print();
$mbx2->print();
|
Prototypeパターンを使用した例 MessageBox.pm package MessageBox {
use Clone qw(clone);
sub new {
my ($class) = @_;
my ($this) = { decoChar => " ",
width => 20,
padding => " ",
message => ""
};
return bless $this, $class;
}
sub setChar {
my ($this, $c) = @_;
$this->{decoChar} = $c;
}
sub setWidth {
my ($this, $w) = @_;
$this->{width} = $w;
}
sub setPadding {
my ($this, $p) = @_;
$this->{padding} = $p;
}
sub setMessage {
my ($this, $m) = @_;
$this->{message} = $m;
}
sub print {
my ($this) = @_;
my strLength = length $this->{$message};
if ($strLength > $this->{width}) {
$this->{message} = substr($this->{$message}, 0, $this->{width});
} else {
my $pl = $this->{width} - $strLength;
$this->{message} .= $this->{padding} x $pl;
}
print $this->{decoChar} x ($this->{width} + 4) . "\n";
print $this->{decoChar} . " " . $this->{message} . " " . $this->{decoChar} . "\n";
print $this->{decoChar} x ($this->{width} + 4) . "\n";
}
sub createClone {
my ($this) = @_;
return clone($this);
}
}
1;
Main.pl use lib qw(./);
use MessageBox;
my $mbx1 = new MessageBox();
$mbx1->setChar('*');
$mbx1->setWidth(20);
$mbx1->setPadding('.');
$mbx1->setMessage("Hello, World");
my $mbx2 = $mbx1->createClone();
$mbx2->setMessage("Ciao, Mondo");
$mbx1->print();
$mbx2->print();
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、Clone を継承しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.rb class MessageBox
def initialize()
@decoChar = ' '
@width = 20
@padding = ' '
@message = ""
end
def setChar(c)
@decoChar = c
end
def setWidth(w)
@width = w
end
def setPadding(p)
@padding = p
end
def setMessage(m)
@message = m
end
def print()
strLength = @message.length
if strLength > @width then
@message = @message.slice(0, @width)
else
pl = @width - strLength
@message = @message.concat(@padding * pl)
end
puts @decoChar * (@width + 4)
puts @decoChar + " " + @message + " " + @decoChar
puts @decoChar * (@width + 4)
end
end
Main.rb require './MessageBox'
mbx1 = MessageBox.new()
mbx1.setChar('*')
mbx1.setWidth(20)
mbx1.setPadding('.')
mbx1.setMessage("Hello, World")
mbx2 = MessageBox.new()
mbx2.setChar('*')
mbx2.setWidth(20)
mbx2.setPadding('.')
mbx2.setMessage("Ciao, Mondo")
mbx1.print()
mbx2.print()
|
Prototypeパターンを使用した例 MessageBox.rb class MessageBox
def initialize()
@decoChar = ' '
@width = 20
@padding = ' '
@message = ""
end
def setChar(c)
@decoChar = c
end
def setWidth(w)
@width = w
end
def setPadding(p)
@padding = p
end
def setMessage(m)
@message = m
end
def print()
strLength = @message.length
if strLength > @width then
@message = @message.slice(0, @width)
else
pl = @width - strLength
@message = @message.concat(@padding * pl)
end
puts @decoChar * (@width + 4)
puts @decoChar + " " + @message + " " + @decoChar
puts @decoChar * (@width + 4)
end
def createClone()
return Marshal.load(Marshal.dump(self))
end
end
Main.rb require './MessageBox'
mbx1 = new MessageBox()
mbx1.setChar('*')
mbx1.setWidth(20)
mbx1.setPadding('.')
mbx1.setMessage("Hello, World")
mbx2 = mbx1.createClone()
mbx2.setMessage("Ciao, Mondo")
mbx1.print()
mbx2.print()
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
Ruby では、Object クラスがフィールドやメソッドをコピーする clone メソッドを持っていますが、浅い(shallow)コピーです。ここでは、Marshalモジュールを利用して、深い(deep)コピーを行っています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.py class MessageBox:
def __init__(self):
self.decoChar = ' '
self.width = 20
self.padding = ' '
self.message = ""
def setChar(self, c):
self.decoChar = c
def setWidth(self, w):
self.width = w
def setPadding(self, p):
self.padding = p
def setMessage(self, m):
self.message = m
def print(self):
strLength = len(self.message)
if strLength > self.width:
self.message = self.message[0, self.width]
else:
pl = self.width - strLength
self.message += self.padding *pl
print(self.decoChar * (self.width + 4))
print(self.decoChar + " " + self.message + " " + self.decoChar)
print(self.decoChar * (self.width + 4))
Main.py from MessageBox import MessageBox
mbx1 = MessageBox()
mbx1.setChar('*')
mbx1.setWidth(20)
mbx1.setPadding('.')
mbx1.setMessage("Hello, World")
mbx2 = MessageBox()
mbx2.setChar('*')
mbx2.setWidth(20)
mbx2.setPadding('.')
mbx2.setMessage("Ciao, Mondo")
mbx1.print()
mbx2.print()
|
Prototypeパターンを使用した例 MessageBox.py import copy
class MessageBox:
def __init__(self):
self.decoChar = ' '
self.width = 20
self.padding = ' '
self.message = ""
def setChar(self, c):
self.decoChar = c
def setWidth(self, w):
self.width = w
def setPadding(self, p):
self.padding = p
def setMessage(self, m):
self.message = m
def print(self):
strLength = len(self.message)
if strLength > self.width:
self.message = self.message[0, self.width]
else:
pl = self.width - strLength
self.message += self.padding * pl
print(self.decoChar * (self.width + 4))
print(self.decoChar + " " + self.message + " " + self.decoChar)
print(self.decoChar * (self.width + 4))
def createClone(self):
return copy.deepcopy(self)
Main.py from MessageBox import MessageBox
mbx1 = MessageBox()
mbx1.setChar('*')
mbx1.setWidth(20)
mbx1.setPadding('.')
mbx1.setMessage("Hello, World")
mbx2 = mbx1.createClone()
mbx2.setMessage("Ciao, Mondo")
mbx1.print()
mbx2.print()
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、copy をインポートしています。deepcopy は新たにオブジェクトを作成し、元のオブジェクト中に見つかったフィールドやメソッドをコピーしています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.php <?php
class MessageBox {
public function setChar($c) {
$this->decoChar = $c;
}
public function setWidth($w) {
$this->width = $w;
}
public function setPadding($p) {
$this->padding = $p;
}
public function setMessage($m) {
$this->message = $m;
}
public function print() {
$strLength = strlen($this->message);
if ($strLength > $this->width) {
$this->message = substr($this->message, 0, $this->width);
}
else {
$pl = $this->width - $strLength;
$this->message .= str_repeat($this->padding, $pl);
}
print str_repeat($this->decoChar, $this->width + 4) . "\n";
print $this->decoChar . " " . $this->message . " " . $this->decoChar . "\n";
print str_repeat($this->decoChar, $this->width + 4) . "\n";
}
}
?>
Main.java <?php
require_once('MessageBox.php');
$mbx1 = new MessageBox();
$mbx1->setChar('*');
$mbx1->setWidth(20);
$mbx1->setPadding('.');
$mbx1->setMessage("Hello, World");
MessageBox $mbx2 = new MessageBox();
mbx2.setChar('*');
$mbx2->setWidth(20);
$mbx2->setPadding('.');
$mbx2->setMessage("Ciao, Mondo");
$mbx1->print();
$mbx2->print();
?>
|
Prototypeパターンを使用した例 MessageBox.php <?php
class MessageBox {
public function setChar($c) {
$this->decoChar = $c;
}
public function setWidth($w) {
$this->width = $w;
}
public function setPadding($p) {
$this->padding = $p;
}
public function setMessage($m) {
$this->message = $m;
}
public function print() {
$strLength = strlen($this->message);
if ($strLength > $this->width) {
$this->message = substr($this->message, 0, $this->width);
}
else {
$pl = $this->width - $strLength;
$this->message .= str_repeat($this->padding, $pl);
}
print str_repeat($this->decoChar, $this->width + 4) . "\n";
print $this->decoChar . " " . $this->message . " " . $this->decoChar . "\n";
print str_repeat($this->decoChar, $this->width + 4) . "\n";
}
public function createClone() {
return clone $this;
}
}
?>
Main.java <?php
require_once('MessageBox.php');
$mbx1 = new MessageBox();
$mbx1->setChar('*');
$mbx1->setWidth(20);
$mbx1->setPadding('.');
$mbx1->setMessage("Hello, World");
$mbx2 = $mbx1->createClone();
$mbx2->setMessage("Ciao, Mondo");
$mbx1->print();
$mbx2->print();
?>
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、java.lang.Cloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 なお、createClone() から呼んでいる clone は、シャロウ・コピーです。 |
|
Prototypeパターンを使用しない例 MessageBox.ts export
class MessageBox {
private decoChar:string = " ";
private width:number = 20;
private padding:string = " ";
private message:string = "";
public setChar(c:string):void {
this.decoChar = c;
}
public setWidth(w:number):void {
this.width = w;
}
public setPadding(p:string):void {
this.padding = p;
}
public setMessage(m:string):void {
this.message = m;
}
public print():void {
let strLength:number = this.message.length;
if (strLength > this.width) {
this.message = this.message.substring(0, this.width);
}
else {
let pl:number = this.width - strLength;
this.message = this.message.concat(this.padding.repeat(pl));
}
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
process.stdout.write(this.decoChar + " " + this.message + " " + this.decoChar + "\n");
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
}
} Main.ts import {MessageBox} from "./MessageBox";
let mbx1:MessageBox = new MessageBox();
mbx1.setChar("*");
mbx1.setWidth(20);
mbx1.setPadding(".");
mbx1.setMessage("Hello, World");
let mbx2:MessageBox = new MessageBox();
mbx2.setChar("*");
mbx2.setWidth(20);
mbx2.setPadding(".");
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
|
Prototypeパターンを使用した例 MessageBox.ts import {Clonable} from "./Clonable";
export
class MessageBox implements Cloneable {
private decoChar:string = " ";
private width:number = 20;
private padding:string = " ";
private message:string = "";
public constructor() {
super();
}
public setChar(c:string):void {
this.decoChar = c;
}
public setWidth(w:number):void {
this.width = w;
}
public setPadding(p:string):void {
this.padding = p;
}
public setMessage(m:string):void {
this.message = m;
}
public print():void {
let strLength:number = this.message.length;
if (strLength > this.width) {
this.message = this.message.substring(0, this.width);
}
else {
let pl:number = this.width - strLength;
this.message = this.message.concat(this.padding.repeat(pl));
}
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
process.stdout.write(this.decoChar + " " + this.message + " " + this.decoChar + "\n");
process.stdout.write(this.decoChar.repeat(this.width + 4) + "\n");
}
public createClone():MessageBox {
return super.clone(this);
}
}
Cloneable.ts const cloneDeep = require('lodash/cloneDeep');
export
class Cloneable {
public clone<T>(obj: T): T {
return cloneDeep(obj);
}
}
Main.ts import {MessageBox} from "./MessageBox";
let mbx1:MessageBox = new MessageBox();
mbx1.setChar("*");
mbx1.setWidth(20);
mbx1.setPadding(".");
mbx1.setMessage("Hello, World");
let mbx2:MessageBox = mbx1.createClone();
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、java.lang.Cloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.swift class MessageBox {
private var decoChar:String = " "
private var width:Int = 20
private var padding:String = " "
private var message:String = ""
public func setChar(_ c:String) {
decoChar = c
}
public func setWidth(_ w:Int) {
width = w
}
public func setPadding(_ p:String) {
padding = p
}
public func setMessage(_ m:String) {
message = m
}
public func _print() {
let strLength:Int = message.count
if strLength > width {
message = String(message.prefix(width))
}
else {
let pl:Int = width - strLength
for _ in 0..<pl {
message += String(padding)
}
}
for _ in 0..<width + 4 {
print(decoChar, terminator:"")
}
print()
print(decoChar + " " + message + " " + decoChar)
for _ in 0..<width + 4 {
print(decoChar, terminator:"")
}
print()
}
} Main.swift let mbx1:MessageBox = MessageBox()
mbx1.setChar("*")
mbx1.setWidth(20)
mbx1.setPadding(".")
mbx1.setMessage("Hello, World")
let mbx2:MessageBox = MessageBox()
mbx2.setChar("*")
mbx2.setWidth(20)
mbx2.setPadding(".")
mbx2.setMessage("Ciao, Mondo")
mbx1._print()
mbx2._print()
|
Prototypeパターンを使用した例 MessageBox.swift class MessageBox {
private var decoChar:String = " "
private var width:Int = 20
private var padding:String = " "
private var message:String = ""
public init() {}
private init(_ mbox:MessageBox) {
decoChar = mbox.decoChar
width = mbox.width
padding = mbox.padding
message = mbox.message
}
public func setChar(_ c:String) {
decoChar = c
}
public func setWidth(_ w:Int) {
width = w
}
public func setPadding(_ p:String) {
padding = p
}
public func setMessage(_ m:String) {
message = m
}
public func _print() {
let strLength:Int = message.count
if strLength > width {
message = String(message.prefix(width))
}
else {
let pl:Int = width - strLength
for _ in 0..<pl {
message += String(padding)
}
}
for _ in 0..<width + 4 {
print(decoChar, terminator:"")
}
print()
print(decoChar + " " + message + " " + decoChar)
for _ in 0..<width + 4 {
print(decoChar, terminator:"")
}
print()
}
public func createClone() -> MessageBox {
return MessageBox(self)
}
}
Main.swift let mbx1:MessageBox = new MessageBox()
mbx1.setChar("*")
mbx1.setWidth(20)
mbx1.setPadding(".")
mbx1.setMessage("Hello, World")
let mbx2:MessageBox = mbx1.createClone()
mbx2.setMessage("Ciao, Mondo")
mbx1._print()
mbx2._print()
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.kt class MessageBox {
var decoChar: Char = ' '
var width: int = 20
var padding: Char = ' '
var message: String = ""
fun print() {
val strLength = message.toByteArray().size
if (strLength > width) {
message = message.substring(0, width)
}
else {
val pl = width - strLength
message += padding.toString().repeat(pl)
}
println(decoChar.toString().repeat(width + 4))
println("$decoChar $message $decoChar")
println(decoChar.toString().repeat(width + 4))
}
} Main.kt fun main() {
val mbx1 = MessageBox()
mbx1.decoChar = '*'
mbx1.width = 20
mbx1.padding = '.'
mbx1.message = "Hello, World"
val mbx2:MessageBox = MessageBox()
mbx2.decoChar = '*'
mbx2.width = 20
mbx2.padding = '.'
mbx2.message = "Ciao, Mondo"
mbx1.print()
mbx2.print()
}
|
Prototypeパターンを使用した例 MessageBox.kt class MessageBox : Cloneable {
var decoChar: Char = ' '
var width: Int = 20
var padding: Char = ' '
var message: String = ""
fun print() {
var strLength = message.toByteArray().size
if (strLength > width) {
message = message.substring(0, width)
}
else {
var pl = this.width - strLength
message += padding.toString().repeat(pl)
}
println(decoChar.toString().repeat(width + 4))
println("$decoChar $message $decoChar")
println(decoChar.toString().repeat(width + 4))
}
fun createClone():MessageBox {
return clone() as MessageBox
}
}
Main.kt fun main() {
val mbx1:MessageBox = MessageBox()
mbx1.decoChar = '*'
mbx1.width = 20
mbx1.padding = '.'
mbx1.message = "Hello, World"
val mbx2:MessageBox = mbx1.createClone()
mbx2.message = "Ciao, Mondo"
mbx1.print()
mbx2.print()
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、java.lang.Cloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.scala class MessageBox {
var decoChar: Char = ' '
var width: int = 20
var padding: Char = ' '
var message: String = ""
def print() {
val strLength = message.length
if (strLength > width) {
message = message.substring(0, width)
}
else {
val pl = width - strLength
message = message.concat(padding.toString() * pl)
}
val dc: String = decoChar.toString()
System.out.println(dc * (width + 4))
System.out.println(dc + " " + message + " " + dc)
System.out.println(dc * (width + 4))
}
} Main.scala object Main {
def main(args: Array[String]) {
val mbx1 = new MessageBox()
mbx1.decoChar = '*'
mbx1.width = 20
mbx1.padding = '.'
mbx1.message = "Hello, World"
val mbx2 = new MessageBox()
mbx2.decoChar = '*'
mbx2.width = 20
mbx2.padding = '.'
mbx2.message = "Ciao, Mondo"
mbx1.print()
mbx2.print()
}
}
|
Prototypeパターンを使用した例 MessageBox.scala class MessageBox extends Cloneable {
var decoChar: Char = ' '
var width: Int = 20
var padding: Char = ' '
var message: String = ""
def print() {
val strLength = message.length
if (strLength > width) {
message = message.substring(0, width)
}
else {
val pl = width - strLength
message = message.concat(padding.toString() * pl)
}
val dc: String = decoChar.toString()
System.out.println(dc * (width + 4))
System.out.println(dc + " " + message + " " + dc)
System.out.println(dc * (width + 4))
}
def createClone():MessageBox {
clone.asInstanceOf[MessageBox]
}
}
Main.scala object Main {
def main(args: Array[String]) {
val mbx1 = MessageBox()
mbx1.decoChar = '*'
mbx1.width = 20
mbx1.padding = '.'
mbx1.message = "Hello, World"
val mbx2 = mbx1.createClone()
mbx2.message = "Ciao, Mondo"
mbx1.print()
mbx2.print()
}
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、java.lang.Cloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.groovy class MessageBox {
String decoChar = " "
int width = 20
char padding = ' '
String message = ""
MessageBox() {}
void print() {
int strLength = message.getBytes().length
if (strLength > width) {
message = message.substring(0, width)
}
else {
int pl = width - strLength
message += padding.toString() * pl
}
System.out.println(decoChar * (width + 4))
System.out.println(decoChar + " " + message + " " + decoChar)
System.out.println(decoChar * (width + 4))
}
}
Main.groovy class Main {
static void main(String[] args) {
MessageBox mbx1 = new MessageBox()
mbx1.decoChar = '*'
mbx1.width = 20
mbx1.padding = '.'
mbx1.message = "Hello, World"
MessageBox mbx2 = new MessageBox()
mbx2.decoChar = '*'
mbx2.width = 20
mbx2.padding = '.'
mbx2.message = "Ciao, Mondo"
mbx1.print()
mbx2.print()
}
}
|
Prototypeパターンを使用した例 MessageBox.groovy class MessageBox implements Cloneable {
String decoChar = " "
int width = 20
char padding = ' '
String message = ""
MessageBox() {}
void print() {
int strLength = message.getBytes().length
if (strLength > width) {
message = message.substring(0, width)
}
else {
int pl = width - strLength
message += padding.toString() * pl
}
System.out.println(decoChar * (width + 4))
System.out.println(decoChar + " " + message + " " + decoChar)
System.out.println(decoChar * (width + 4))
}
Cloneable createClone() {
MessageBox p = null
try {
p = (Cloneable) clone()
}
catch (CloneNotSupportedException e) {
e.printStackTrace()
}
return p
}
}
Main.groovy class Main {
static void main(String[] args) {
MessageBox mbx1 = new MessageBox()
mbx1.decoChar = '*'
mbx1.width = 20
mbx1.padding = '.'
mbx1.message = "Hello, World"
MessageBox mbx2 = mbx1.createClone()
mbx2.message = "Ciao, Mondo"
mbx1.print()
mbx2.print()
}
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
MessageBox クラスは、java.lang.Cloneable を継承(インタフェースなのでインプリメント)しています。 一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 なお、createClone() から呼んでいる clone() は、java.lang.Object.clone() です。 |
|
Prototypeパターンを使用しない例 MessageBox.go import (
"fmt"
"strings"
)
type MessageBox struct {
DecoChar rune
Width int
Padding rune
Message string
}
func (self *MessageBox) Print() {
var strLength = len(self.Message)
if strLength > self.Width {
self.Message = self.Message[:self.Width]
} else {
var pl = self.Width - strLength
self.Message += strings.Repeat(string(self.padding), pl)
}
fmt.Println(strings.Repeat(string(self.DecoChar), self.Width + 4))
fmt.Println(string(self.DecoChar) + " " + self.message + " " + string(self.DecoChar))
fmt.Println(strings.Repeat(string(self.DecoChar), self.Width + 4))
}
}
func NewMessageBox() *MessageBox {
return &MessageBox{}
}
Main.go func main() {
var mbx1 = NewMessageBox()
mbx1.DecoChar = '*'
mbx1.Width = 20
mbx1.Padding = '.'
mbx1.Message = "Hello, World"
var mbx2 = NewMessageBox()
mbx2.DecoChar = '*'
mbx2.Width = 20
mbx2.Padding = '.'
mbx2.Message = "Ciao, Mondo"
mbx1.Print()
mbx2.Print()
}
|
Prototypeパターンを使用した例 MessageBox.go import (
"fmt"
"strings"
)
type MessageBox struct {
DecoChar rune
Width int
Padding rune
Message string
}
func (self *MessageBox) Print() {
var strLength = len(self.Message)
if strLength > self.Width {
self.Message = self.Message[:self.Width]
} else {
var pl = self.Width - strLength
self.Message += strings.Repeat(string(self.padding), pl)
}
fmt.Println(strings.Repeat(string(self.DecoChar), self.Width + 4))
fmt.Println(string(self.DecoChar) + " " + self.message + " " + string(self.DecoChar))
fmt.Println(strings.Repeat(string(self.DecoChar), self.Width + 4))
}
func (self *MessageBox) Clone() *MessageBox {
var copy = *self
return ©
}
func NewMessageBox() *MessageBox {
return &MessageBox{}
}
Main.go func main {
var mbx1 = NewMessageBox()
mbx1.DecoChar = '*'
mbx1.Width = 20
mbx1.Padding = '.'
mbx1.Message = "Hello, World"
var mbx2 = mbx1.Clone()
mbx2.Message = "Ciao, Mondo"
mbx1.Print()
mbx2.Print()
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 messagebox.d import std.stdio;
import std.string;
public class MessageBox {
private char decoChar = ' ';
private int width = 20;
private char padding = ' ';
private String message = "";
public this() {}
public void setChar(in char c) {
decoChar = c;
}
public void setWidth(in int w) {
width = w;
}
public void setPadding(in char p) {
padding = p;
}
public void setMessage(in String m) {
message = m;
}
public void print() {
int strLength = message.length;
if (strLength > width) {
message = message[0..width];
} else {
foreach (int i; 0..width - strLength)
message ~= padding;
}
foreach (int i; 0..width + 4)
write(decoChar);
writeln();
writefln("%c %s %c", decoChar, message, decoChar);
foreach (int i; 0..width + 4)
write(decoChar);
writeln();
}
}
main.d import messagebox;
public int main() {
MessageBox mbx1 = new MessageBox();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage("Hello, World");
MessageBox mbx2 = new MessageBox();
mbx2.setChar('*');
mbx2.setWidth(20);
mbx2.setPadding('.');
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
return 0;
}
|
Prototypeパターンを使用した例 messagebox.d import std.stdio;
public class MessageBox {
private char decoChar = ' ';
private int width = 20;
private char padding = ' ';
private String message = "";
public this() {}
public this(MessageBox b) {
this.decoChar = b.decoChar;
this.width = b.width;
this.padding = b.padding;
this.message = b.message;
}
public void setChar(char c) {
decoChar = c;
}
public void setWidth(int w) {
width = w;
}
public void setPadding(char p) {
padding = p;
}
public void setMessage(String m) {
message = m;
}
public void print() {
int strLength = message.getBytes().length;
if (strLength > width) {
message = message[0..width];
} else {
foreach (int i; 0..width - strLength)
message ~= padding;
}
foreach (int i; 0..width + 4)
write(decoChar);
writeln();
writefln("%c %s %c", decoChar, message, decoChar);
foreach (int i; 0..width + 4)
write(decoChar);
writeln();
}
public MessageBox createClone() {
return new MessageBox(this);
}
}
main.d import messagebox;
public int main() {
MessageBox mbx1 = new MessageBox();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage("Hello, World");
MessageBox mbx2 = mbx1.createClone();
mbx2.setMessage("Ciao, Mondo");
mbx1.print();
mbx2.print();
return 0;
}
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |
|
Prototypeパターンを使用しない例 MessageBox.pas unit UnitMessageBox;
interface
uses
System.StrUtils;
type
MessageBox = class
private
var decoChar:Char;
var width:integer;
var padding:Char;
var message:string;
public
procedure setChar(c:Char);
procedure setWidth(w:integer);
procedure setPadding(p:Char);
procedure setMessage(m:string);
procedure print();
end;
implementation
procedure MessageBox.setChar(c:Char);
begin
decoChar := c;
end;
procedure MessageBox.setWidth(w:integer);
begin
width := w;
end;
procedure MessageBox.setPadding(p:Char);
begin
padding := p;
end;
procedure MessageBox.setMessage(m:string);
begin
message := m;
end;
procedure MessageBox.print();
var strLength:integer;
var pl:integer;
begin
strLength := Length(message);
if strLength > width then begin
message := Copy(message, 0, width);
end
else begin
pl := width - strLength;
message := message + DupeString(padding, pl);
end;
Writeln(DupeString(decoChar, width + 4));
Writeln(decoChar + ' ' + message + ' ' + decoChar);
Writeln(DupeString(decoChar, width + 4));
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitMessageBox;
var mbx1:MessageBox;
var mbx2:MessageBox;
begin
mbx1 := MessageBox.Create();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage('Hello, World');
mbx2 := MessageBox.Create();
mbx2.setChar('*');
mbx2.setWidth(20);
mbx2.setPadding('.');
mbx2.setMessage('Ciao, Mondo');
mbx1.print();
mbx2.print();
mbx1.Free;
mbx2.Free;
|
Prototypeパターンを使用した例 MessageBox.pas unit UnitMessageBox;
interface
uses
System.StrUtils;
type
MessageBox = class
private
var decoChar:Char;
var width:integer;
var padding:Char;
var message:string;
public
constructor Create(); overload;
constructor Create(b:MessageBox); overload;
procedure setChar(c:Char);
procedure setWidth(w:integer);
procedure setPadding(p:Char);
procedure setMessage(m:string);
procedure print();
function createClone():MessageBox;
end;
implementation
constructor MessageBox.Create();
begin
inherited Create();
end;
constructor MessageBox.Create(b:MessageBox);
begin
inherited Create();
decoChar := b.decoChar;
width := b.width;
padding := b.padding;
message := b.message;
end;
procedure MessageBox.setChar(c:Char);
begin
decoChar := c;
end;
procedure MessageBox.setWidth(w:integer);
begin
width := w;
end;
procedure MessageBox.setPadding(p:Char);
begin
padding := p;
end;
procedure MessageBox.setMessage(m:string);
begin
message := m;
end;
procedure MessageBox.print();
var strLength:integer;
var pl:integer;
begin
strLength := Length(message);
if strLength > width then begin
message := Copy(message, 0, width);
end
else begin
pl := width - strLength;
message := message + DupeString(padding, pl);
end;
Writeln(DupeString(decoChar, width + 4));
Writeln(decoChar + ' ' + message + ' ' + decoChar);
Writeln(DupeString(decoChar, width + 4));
end;
function MessageBox.createClone():MessageBox;
begin
Result := MessageBox.Create(self);
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitMessageBox;
var mbx1:MessageBox;
var mbx2:MessageBox;
begin
mbx1 := MessageBox.Create();
mbx1.setChar('*');
mbx1.setWidth(20);
mbx1.setPadding('.');
mbx1.setMessage('Hello, World');
mbx2 := mbx1.createClone();
mbx2.setMessage('Ciao, Mondo');
mbx1.print();
mbx2.print();
mbx1.Free;
mbx2.Free;
|
|
MessageBox のインスタンスを2つ作りました。これら2つのインスタンスは同じ設定なのですが、それぞれ別のインスタンスなので、生成された後、個別に枠の文字や横幅、文字の不足する部分に埋める文字を指定しています。この例では、3つだけでしたが、これが何十個もあったら、そして、少しずつ違う設定だったら... 非常に大変であるということが想像できると思います。 |
一つ目のインスタンスでは、MessageBox クラスのインスタンスを生成し、メソッドを呼んでフィールドに値を設定しています。しかし、2つ目のインスタンスには、一つ目のインスタンスのコピーを設定しているだけです。これだけです。設定しなければならない項目が何十個あろうが、 createClone() の結果を代入してあげればよいだけなのです。 設定する内容が少しずつ違っていても、コピーをした後、違うところだけ変えてあげればよいのです。 |