Proxyパターン
要求を代理人オブジェクトが受け取って処理する
Proxyとは「代理人」という意味です。Proxyパターンは、要求を代理人オブジェクトが受け取って処理するパターンです。
現実世界で代理人というと、弁護士や税理士など本人ができない仕事をするというイメージがありますが、Proxyパターンにおける代理人オブジェクトは、本人でなくてもできるような処理を任されます。そして代理人オブジェクトでできない処理は本人オブジェクトが引き受け、処理します。この任せる行為が「委譲」です。
今日の予定を聞いたら、その予定を知っている友人が代わりに答えている感じです。でも、友人は明日のことは分からないので、それは本人が答えます。
つまり、間に挟んで、Proxyサーバ同様、対象オブジェクトの呼び出しのタイミングを変えたり、キャッシュを返したりして、対象オブジェクトの代わりの処理をしたりします。呼び出し側はProxyであることを意識しません。
このとき、呼び出しのタイミングを変えるということは次のような場合です。
生成に非常に時間が掛かる、メモリをたくさん使うなどのインスタンスや、起動時には利用するかどうか分からない機能のインスタンスをプログラムの最初に生成していては、アプリケーションの起動に時間が掛かり利用者を待たせてしまうことになります。実際に、こういう機能を利用するときになって始めて生成するというようにした方が利用者のストレスが少なくなるわけです。
また、キャッシュを返すとは次のような場合です。
一度読み込んだ情報であれば、その情報が変わらないということならばもう一度読み込む必要はないはずです。このようなとき、Proxyは読み込んだ振りをして、前に読み込んであった情報を返します。もし、まだ読み込んでいない情報ならば、本人に読み込むことを任せるわけです。
Proxyパターンの工夫は、Decoratorパターンと基本的に同じなのです(両者を比べてみてください)。では、どこが違うのか。ここが、重要なポイントです。それは、Decoratorパターンは、クラスを作る人が利用するものであり、Proxyパターンは、クラスを使う人が利用するものだということです。
同じ工夫であっても、クラスを作る人の視点から見ればDecoratorパターンであり、クラスを使う人の視点から見ればProxyパターンなのです。
例題
時間によって、適切な挨拶を返す GreetingOfEncounter というクラスがあります。これを利用して、「○○さん、」を先につけるクラスを作りなさい。
山田さん、こんにちは
山田さん、こんばんは
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.java public class MyGreeting extends GreetingOfEncounter {
private String name;
public void setName(String name) {
this.name = name;
}
public String getGreeting() {
return name + "さん、" + super.getGreeting();
}
}
Main.java public class Main {
public static void main(String[] args) {
MyGreeting g = new MyGreeting();
g.setName("山田");
g.setClock(7);
System.out.println(g.getGreeting());
g.setClock(14);
System.out.println(g.getGreeting());
g.setClock(21);
System.out.println(g.getGreeting());
}
}
|
Proxyパターンを使用した例 MyGreeting.java public class MyGreeting {
private String name;
private int hour;
private String className;
private IGreeting real;
public MyGreeting(String className) {
this.className = className;
}
public void setName(String name) {
this.name = name;
}
public synchronized void setClock(int hour) {
if (real != null) {
real.setClock(hour);
}
this.hour = hour;
}
public String getGreeting() {
realize();
real.setClock(hour);
return name + "さん、" + real.getGreeting();
}
public synchronized void realize() {
if (real == null) {
try {
real = (IGreeting) Class.forName(className).newInstance();
} catch (ClassNotFoundException e) {
System.err.println(className + " not found");
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
Main.java public class Main {
public static void main(String[] args) {
MyGreeting g = new MyGreeting("GreetingOfEncounter");
g.setName("山田");
g.setClock(7);
System.out.println(g.getGreeting());
g.setClock(14);
System.out.println(g.getGreeting());
g.setClock(21);
System.out.println(g.getGreeting());
}
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 myGreeting.h #include "greetingOfEncounter.h"
class MyGreeting : public GreetingOfEncounter
{
private:
std::string name;
public:
MyGreeting(void);
virtual ~MyGreeting(void);
void setName(std::string);
std::string meet(void);
}; myGreeting.cpp #include "myGreeting.h"
using namespace std;
MyGreeting::MyGreeting(void) {}
MyGreeting::~MyGreeting(void) {}
void MyGreeting::setName(string name) {
this->name = name;
}
string MyGreeting::meet(void) {
return name + "さん、" + getMessage();
}
main.cpp #include <iostream>
using namespace std;
#include "myGreeting.h"
int main() {
MyGreeting g;
g.setName("山田");
g.setClock(7);
cout << g.meet() << endl;
g.setClock(14);
cout << g.meet() << endl;
g.setClock(21);
cout << g.meet() << endl;
return 0;
}
|
Proxyパターンを使用した例 myGreeting.h #include "greetingOfEncounter.h"
class MyGreeting
{
private:
std::string name;
int hour;
Greeting* real;
public:
MyGreeting(void);
virtual ~MyGreeting(void);
void setName(std::string);
void setClock(int);
std::string meet(void);
void realize(void);
}; myGreeting.cpp #include "myGreeting.h"
using namespace std;
MyGreeting::MyGreeting(void) : real(0) {}
MyGreeting::~MyGreeting(void) {
if (real != 0) {
delete real;
}
}
void MyGreeting::setName(string name) {
this->name = name;
}
void MyGreeting::setClock(int hour) {
if (real != 0)
real->setClock(hour);
this->hour = hour;
}
string MyGreeting::meet(void) {
realize();
real->setClock(hour);
return name + "さん、" + real->getMessage();
}
void MyGreeting::realize(void) {
if (real == 0) {
real = new GreetingOfEncounter();
}
}
main.cpp #include <iostream>
using namespace std;
#include "myGreeting.h"
int main() {
MyGreeting g;
g.setName("山田");
g.setClock(7);
cout << g.meet() << endl;
g.setClock(14);
cout << g.meet() << endl;
g.setClock(21);
cout << g.meet() << endl;
return 0;
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxy パターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.cs class MyGreeting : GreetingOfEncounter
{
private string name;
public void SetName(string name)
{
this.name = name;
}
public string Meeting()
{
return name + "さん、" + Greeting();
}
}
Program.cs class Program
{
static void Main(string[] args)
{
MyGreeting g = new MyGreeting();
g.SetName("山田");
g.SetClock(7);
Console.WriteLine(g.Meeting());
g.SetClock(14);
Console.WriteLine(g.Meeting());
g.SetClock(21);
Console.WriteLine(g.Meeting());
}
}
|
Proxyパターンを使用した例 MyGreeting.cs class MyGreeting
{
private string name;
private int hour;
private IGreeting real = null;
public void SetName(string name)
{
this.name = name;
}
public void SetClock(int hour)
{
if (real != null)
{
real.SetClock(hour);
}
this.hour = hour;
}
public string Meeting()
{
Realize();
real.SetClock(hour);
return name + "さん、" + real.Greeting();
}
private void Realize()
{
if (real == null)
{
real = new GreetingOfEncounter();
}
}
}
Program.cs class Program
{
static void Main(string[] args)
{
MyGreeting g = new MyGreeting();
g.SetName("山田");
g.SetClock(7);
Console.WriteLine(g.Meeting());
g.SetClock(14);
Console.WriteLine(g.Meeting());
g.SetClock(21);
Console.WriteLine(g.Meeting());
}
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、SetName や SetClock はするけれど、Meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxy パターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、Meeting が呼ばれて(その中から Realize が呼ばれて)からです。これだと、 SetName や SetClock はしたけれど、Meeting しなかったという場合でも、無駄はありません。 |
既存クラス
|
Proxyパターンを使用しない例 GreetingOfEncounter.vb Public Class GreetingOfEncounter
Implements IGreeting
Private state As Integer
Public Function Greeting() As String Implements IGreeting.Greeting
If state = 1 Then
Return "おはよう"
ElseIf state = 2 Then
Return "こんにちは"
Else
Return "こんばんは"
End If
End Function
Public Sub SetClock(ByVal hour As Integer) Implements IGreeting.setClock
If hour < 4 OrElse hour >= 19 Then
state = 3
ElseIf hour < 10 Then
state = 1
Else
state = 2
End If
End Sub
End Class
MyGreeting.vb Public Class MyGreeting Inherits GreetingOfEncounter
Private name As String
Public Sub SetName(ByVal name As String)
Me.name = name
End Sub
Public Function Meeting() As String
Return name & "さん、" & Greeting()
End Function
End Class
Program.vb Module Main
Sub Main()
Dim g As MyGreeting = New MyGreeting()
g.SetName("山田")
g.SetClock(7)
Console.WriteLine(g.Meeting())
g.SetClock(14)
Console.WriteLine(g.Meeting())
g.SetClock(21)
Console.WriteLine(g.Meeting())
End Sub
End Module
|
Proxyパターンを使用した例 GreetingOfEncounter.vb Public Class GreetingOfEncounter Implements IGreeting
Private state As Integer
Public Function Greeting() As String Implements IGreeting.greeting
If state = 1 Then
Return "おはよう"
ElseIf state = 2 Then
Return "こんにちは"
Else
Return "こんばんは"
End If
End Function
Public Sub SetClock(ByVal hour As Integer) Implements IGreeting.setClock
If hour < 4 OrElse hour >= 19 Then
state = 3
ElseIf hour > 10 Then
state = 1
Else
state = 2
End If
End Sub
End Class
MyGreeting.vb Public Class MyGreeting
Private name As String
Private hour As Integer
Private real As IGreeting = Nothing
Public Sub SetName(ByVal name As String)
Me.name = name
End Sub
Public Sub SetClock(ByVal hour As Integer)
If real IsNot Nothing Then
real.SetClock(hour)
End If
Me.hour = hour
End Sub
Public Function Meeting() As String
Realize()
real.SetClock(hour)
Return name & "さん、" & real.Greeting()
End Function
Private Sub Realize()
If real Is Nothing Then
real = New GreetingOfEncounter()
End If
End Sub
End Class
Program.vb Module Main
Sub Main()
Dim g As MyGreeting = New MyGreeting()
g.SetName("山田")
g.SetClock(7)
Console.WriteLine(g.Meeting())
g.SetClock(14)
Console.WriteLine(g.Meeting())
g.SetClock(21)
Console.WriteLine(g.Meeting())
End Sub
End Module
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、SetName や SetClock はするけれど、Meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxy パターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、Meeting が呼ばれて(その中から Realize が呼ばれて)からです。これだと、 SetName や SetClock はしたけれど、Meeting しなかったという場合でも、無駄はありません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.js const GreetingOfEncounter =
require("./GreetingOfEncounter.js");
module.exports = class MyGreeting
extends GreetingOfEncounter {
setName(name) {
this.name = name;
}
getGreeting() {
return this.name + "さん、" + super.getGreeting();
}
}
Main.js const MyGreeting = require("./MyGreeting.js");
let g = new MyGreeting();
g.setName("山田");
g.setClock(7);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(14);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(21);
process.stdout.write(g.getGreeting() + "\n");
|
Proxyパターンを使用した例 MyGreeting.js module.exports = class MyGreeting {
constructor(className) {
this.className = className;
}
setName(name) {
this.name = name;
}
setClock(hour) {
if (this.real != null) {
this.real.setClock(hour);
}
this.hour = hour;
}
getGreeting() {
this.realize();
this.real.setClock(this.hour);
return this.name + "さん、" + this.real.getGreeting();
}
realize() {
if (this.real == null) {
let Class = require("./" + this.className + ".js"); // パス注意
this.real = new Class();
}
}
}
Main.js const MyGreeting = require("./MyGreeting.js");
let g = new MyGreeting("GreetingOfEncounter");
g.setName("山田");
g.setClock(7);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(14);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(21);
process.stdout.write(g.getGreeting() + "\n");
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.pm package MyGreeting {
use base qw(GreetingOfEncounter);
sub new {
my ($class) = @_;
return bless {}, $class;
}
sub setName {
my ($this, $name) = @_;
$this->{name} = $name;
}
sub getGreeting() {
return $this->{name} . "さん、" . $this->SUPER::getGreeting();
}
}
1;
Main.pl use lib qw(./);
use MyGreeting;
my $g = new MyGreeting();
$g->setName("山田");
$g->setClock(7);
print $g->getGreeting() . "\n";
$g->setClock(14);
print $g->getGreeting() . "\n";
$g->setClock(21);
print $g->getGreeting() . "\n";
|
Proxyパターンを使用した例 MyGreeting.pm package MyGreeting {
sub new {
my ($class, $className) = @_;
my $this = { className => $className,
real => undef
};
return bless $this, $class;
}
sub setName {
my ($this, $name) = @_;
$this->{name} = $name;
}
sub setClock {
my ($this, $hour) = @_;
if ($this->{real} != undef) {
$this->{real}->setClock($hour);
}
$this->{hour} = $hour;
}
sub getGreeting {
my ($this) = @_;
$this->realize();
$this->{real}->setClock($this->{hour});
return $this->{name} . "さん、". $this->{real}->getGreeting();
}
sub realize {
my ($this) = @_;
if ($this->{real} == undef) {
my $className = $this->{className};
eval "require $className";
$this->{real} = eval "new ${className}()";
}
}
}
1;
Main.pl use lib qw(./);
use MyGreeting;
my $g = new MyGreeting("GreetingOfEncounter");
$g->setName("山田");
$g->setClock(7);
print $g->getGreeting() + "\n";
$g->setClock(14);
print $g->getGreeting() + "\n";
$g->setClock(21);
print $g->getGreeting() + "\n";
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.rb require './GreetingOfEncounter'
class MyGreeting < GreetingOfEncounter
def setName(name)
@name = name
end
def getGreeting()
return @name + "さん、" + super
end
end
Main.rb require './MyGreeting'
g = MyGreeting.new()
g.setName("山田")
g.setClock(7)
puts g.getGreeting()
g.setClock(14)
puts g.getGreeting()
g.setClock(21)
puts g.getGreeting()
|
Proxyパターンを使用した例 MyGreeting.rb class MyGreeting
def initialize(className)
@className = className
end
def setName(name)
@name = name
end
def setClock(hour)
if @real != nil then
@real.setClock(hour)
end
@hour = hour
end
def getGreeting()
realize()
@real.setClock(@hour)
return @name + "さん、" + @real.getGreeting()
end
def realize()
if @real == nil then
eval("require './" + @className + "'")
@real = eval(@className + ".new()")
end
end
end
Main.rb require './MyGreeting'
g = MyGreeting.new("GreetingOfEncounter")
g.setName("山田")
g.setClock(7)
puts g.getGreeting()
g.setClock(14)
puts g.getGreeting()
g.setClock(21)
puts g.getGreeting()
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.pv from GreetingOfEncounter import GreetingOfEncounter
class MyGreeting(GreetingOfEncounter):
def setName(self, name):
self.name = name
def getGreeting(self):
return self.name + "さん、" + super(MyGreeting, self).getGreeting()
Main.py from MyGreeting import MyGreeting
g = MyGreeting()
g.setName("山田")
g.setClock(7)
print(g.getGreeting())
g.setClock(14)
print(g.getGreeting())
g.setClock(21)
print(g.getGreeting())
|
Proxyパターンを使用した例 MyGreeting.py class MyGreeting:
def __init__(self, className):
self.className = className
self.real = None
def setName(self, name):
self.name = name;
def setClock(self, hour):
if self.real != None:
self.real.setClock(self.real, hour)
self.hour = hour
def getGreeting(self):
self.realize()
self.real.setClock(self.real, self.hour)
return self.name + "さん、" + self.real.getGreeting(self.real)
def realize(self):
if self.real == None:
m = __import__(self.className)
self.real = getattr(m, self.className)
Main.py from MyGreeting import MyGreeting
g = MyGreeting("GreetingOfEncounter")
g.setName("山田")
g.setClock(7)
print(g.getGreeting())
g.setClock(14)
print(g.getGreeting())
g.setClock(21)
print(g.getGreeting())
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.php <?php
require_once('GreetingOfEncounter.php');
class MyGreeting extends GreetingOfEncounter {
private $name;
public function setName($name) {
$this->name = $name;
}
public function getGreeting() {
return $this->name . "さん、" . parent::getGreeting();
}
}
?>
Main.php <?php
require_once('MyGreeting.php');
$g = new MyGreeting();
$g->setName("山田");
$g->setClock(7);
print $g->getGreeting() . "\n";
$g->setClock(14);
print $g->getGreeting() . "\n";
$g->setClock(21);
print $g->getGreeting() . "\n";
?>
|
Proxyパターンを使用した例 MyGreeting.php <?php
class MyGreeting {
private $name;
private $hour;
private $className;
private $real;
public function __construct($className) {
$this->className = $className;
}
public function setName($name) {
$this->name = $name;
}
public function setClock($hour) {
if ($this->real != null) {
$this->real->setClock($hour);
}
$this->hour = $hour;
}
public function getGreeting() {
$this->realize();
$this->real->setClock($this->$hour);
return $this->name + "さん、" + $this->real->getGreeting();
}
public function realize() {
if ($this->real == null) {
require_once($this->className . ".php");
$reflClass = new \ReflectionClass($this->className);
$this->real = $reflClass->newInstance();
}
}
}
?>
Main.php <?php
require_once('MyGreeting.php');
$g = new MyGreeting("GreetingOfEncounter");
$g->setName("山田");
$g->setClock(7);
print $g->getGreeting() . "\n";
$g->setClock(14);
print $g->getGreeting() . "\n";
$g->setClock(21);
print $g->getGreeting() . "\n";
?>
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.ts import {GreetingOfEncounter} from "./GreetingOfEncounter";
export
class MyGreeting extends GreetingOfEncounter {
private name:string;
public setName(name:string):void {
this.name = name;
}
public getGreeting():string {
return this.name + "さん、" + super.getGreeting();
}
}
Main.ts import {MyGreeting} from "./MyGreeting";
let g:MyGreeting = new MyGreeting();
g.setName("山田");
g.setClock(7);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(14);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(21);
process.stdout.write(g.getGreeting() + "\n");
|
Proxyパターンを使用した例 MyGreeting.ts import {IGreeting} from "./IGreeting";
export
class MyGreeting {
private className:any;
private name:string;
private real:IGreeting;
private hour:number;
public constructor(className:any) {
this.className = className;
}
public setName(name:string):void {
this.name = name;
}
public setClock(hour:number):void {
if (this.real != null) {
this.real.setClock(hour);
}
this.hour = hour;
}
public getGreeting():string {
this.realize();
this.real.setClock(this.hour);
return this.name + "さん、" + this.real.getGreeting();
}
public realize():void {
if (this.real == null) {
this.real = new this.className();
}
}
}
Main.ts import {MyGreeting} from "./MyGreeting";
import {GreetingOfEncounter} from "./GreetingOfEncounter";
let g:MyGreeting = new MyGreeting(GreetingOfEncounter);
g.setName("山田");
g.setClock(7);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(14);
process.stdout.write(g.getGreeting() + "\n");
g.setClock(21);
process.stdout.write(g.getGreeting() + "\n");
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.swift public class MyGreeting : GreetingOfEncounter {
private var name:String = ""
public func setName(_ name:String) {
self.name = name
}
public override func getGreeting() -> String {
return name + "さん、" + super.getGreeting()
}
}
Main.swift let g:MyGreeting = MyGreeting()
g.setName("山田")
g.setClock(7)
print(g.getGreeting())
g.setClock(14)
print(g.getGreeting())
g.setClock(21)
print(g.getGreeting())
|
Proxyパターンを使用した例 MyGreeting.swift import Foundation
class MyGreeting {
private var className:String
private var name:String = ""
private var hour:Int = 0
private var real:IGreeting!
public init(_ className:String) {
self.className = className
}
public func setName(_ name:String) {
self.name = name
}
public func setClock(_ hour:Int) {
if real != nil {
real.setClock(hour)
}
self.hour = hour
}
public func getGreeting() -> String {
realize()
real!.setClock(hour)
return name + "さん、" + real.getGreeting()
}
public func realize() {
if real == nil {
real = GreetingOfEncounter()
}
}
}
Main.swift let g:MyGreeting = MyGreeting("GreetingOfEncounter")
g.setName("山田")
g.setClock(7)
print(g.getGreeting())
g.setClock(14)
print(g.getGreeting())
g.setClock(21)
print(g.getGreeting())
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.kt class MyGreeting : GreetingOfEncounter() {
lateinit var name: String
override fun getGreeting(): String {
return name + "さん、" + super.getGreeting()
}
}
Main.kt fun main() {
let g = MyGreeting()
g.name = "山田"
g.setClock(7)
println(g.getGreeting())
g.setClock(14);
println(g.getGreeting())
g.setClock(21);
println(g.getGreeting())
}
|
Proxyパターンを使用した例 MyGreeting.kt class MyGreeting(val className: String) {
lateinit var name: String
private var real: IGreeting? = null
private var hour: Int = 0
@Synchronized
fun setClock(hour: Int) {
if (real != null) {
real!!.setClock(hour)
}
this.hour = hour
}
fun getGreeting(): String {
realize()
real!!.setClock(hour)
return name + "さん、" + real!!.getGreeting()
}
@Synchronized
fun realize() {
if (real == null) {
real = Class.forName(className).newInstance() as IGreeting
}
}
}
Main.kt fun main() {
val g = MyGreeting("jp.noor.wasika.GreetingOfEncounter") // パッケージ.クラス
g.name = "山田"
g.setClock(7)
println(g.getGreeting())
g.setClock(14)
println(g.getGreeting())
g.setClock(21)
println(g.getGreeting())
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.scala class MyGreeting extends GreetingOfEncounter {
private var name: String = null
def setName(name: String) {
this.name = name
}
override def getGreeting(): String = name + "さん、" + super.getGreeting()
}
}
Main.scala object Main {
def main(args: Array[String]) {
val g = new MyGreeting()
g.setName("山田")
g.setClock(7)
System.out.println(g.getGreeting())
g.setClock(14);
System.out.println(g.getGreeting())
g.setClock(21);
System.out.println(g.getGreeting())
}
}
|
Proxyパターンを使用した例 MyGreeting.scala class MyGreeting(val className: String) {
private var name: String
private var real: IGreeting = null
private var hour: Int = 0
def setName(name: String) {
this.name = name
}
def setClock(hour: Int) {
if (real != null) {
real.setClock(hour)
}
this.hour = hour
}
def getGreeting(): String = {
realize()
real.setClock(hour)
name + "さん、" + real.getGreeting()
}
def realize() {
if (real == null) {
try real = Class.forName(className).newInstance().asInstanceOf[IGreeting]
catch {
case _: ClassNotFoundException =>
System.err.println(className + " not found")
}
}
}
}
Main.scala object Main {
def main(args: Array[String]) {
val g = new MyGreeting("jp.noor.wasika.GreetingOfEncounter") // パッケージ.クラス
g.setName("山田")
g.setClock(7)
System.out.println(g.getGreeting())
g.setClock(14)
System.out.println(g.getGreeting())
g.setClock(21)
System.out.println(g.getGreeting())
}
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.groovy class MyGreeting extends GreetingOfEncounter {
private String name
String getGreeting() {
return name + "さん、" + super.getGreeting()
}
}
Main.groovy class Main {
static void main(String[] args) {
MyGreeting g = new MyGreeting();
g.name = "山田"
g.setClock(7)
System.out.println(g.getGreeting())
g.setClock(14)
System.out.println(g.getGreeting())
g.setClock(21)
System.out.println(g.getGreeting())
}
}
|
Proxyパターンを使用した例 MyGreeting.groovy class MyGreeting {
private String name
private int hour
private String className
private IGreeting real
MyGreeting(String className) {
this.className = className
}
synchronized void setClock(int hour) {
if (real != null) {
real.setClock(hour)
}
this.hour = hour
}
String getGreeting() {
realize()
real.setClock(hour)
return name + "さん、" + real.getGreeting()
}
synchronized void realize() {
if (real == null) {
try {
real = (IGreeting) Class.forName(className).newInstance()
} catch (ClassNotFoundException e) {
System.err.println(className + " not found")
} catch (Exception e) {
e.printStackTrace()
}
}
}
}
Main.groovy public class Main {
public static void main(String[] args) {
MyGreeting g = new MyGreeting("jp.noor.wasika.GreetingOfEncounter") // package.class
g.name = "山田"
g.setClock(7)
System.out.println(g.getGreeting())
g.setClock(14)
System.out.println(g.getGreeting())
g.setClock(21)
System.out.println(g.getGreeting())
}
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.go type MyGreeting struct {
*GreetingOfEncounter {
self.Name string
}
func (self *MyGreeting) GetGreeting() string {
return name + "さん、" + super.getGreeting()
}
Main.groovy func Main {
var g = NewMyGreeting()
g.Name = "山田"
g.SetClock(7)
fmt.Printf(g.GetGreeting())
g.setClock(14)
fmt.Printf(g.GetGreeting())
g.setClock(21)
fmt.Printf(g.GetGreeting())
}
|
Proxyパターンを使用した例 MyGreeting.go import "reflect"
type MyGreeting struct {
Name string
hour int
className string
real IGreeting
}
func (self *MyGreeting) SetClock(hour int) {
if self.real != null {
self.real.SetClock(hour)
}
self.hour = hour
}
func (self *MyGreeting) GetGreeting() {
self.realize()
self.real.SetClock(self.hour)
return self.Name + "さん、" + self.real.GetGreeting()
}
func (self *MyGreeting) realize() {
if self.real == nil {
self.real = NewGreetingOfEncounter()
}
}
func NewMyGreeting(className string) *MyGreeting {
return &MyGreeting {
className: className,
}
}
Main.go import "fmt"
func main() {
var g = NewMyGreeting("jp.noor.wasika.GreetingOfEncounter") // package.class
g.Name = "山田"
g.SetClock(7)
fmt.Println(g.GetGreeting())
g.SetClock(14)
fmt.Println(g.GetGreeting())
g.SetClock(21)
fmt.Println(g.GetGreeting())
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(main)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 mygreeting.d import greetingofencounter;
public class MyGreeting : GreetingOfEncounter {
private string name;
public void setName(in string name) {
this.name = name;
}
public string getGreeting() {
return name ~ "さん、" ~ super.getGreeting();
}
}
main.d import mygreeting;
int main() {
MyGreeting g = new MyGreeting();
g.setName("山田");
g.setClock(7);
printfln(g.getGreeting());
g.setClock(14);
printfln(g.getGreeting());
g.setClock(21);
printfln(g.getGreeting());
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
Proxyパターンを使用した例 mygreeting.d import igreeting;
import greetingofencounter;
public class MyGreeting {
private string name;
private int hour;
private IGreeting _real;
public void setName(in string name) {
this.name = name;
}
public void setClock(in int hour) {
if (_real !is null) {
synchronized {
_real.setClock(hour);
}
}
this.hour = hour;
}
public string getGreeting() {
realize();
_real.setClock(hour);
return name ~ "さん、" ~ _real.getGreeting();
}
public void realize() {
if (_real is null) {
synchronized {
_real = new GreetingOfEncounter();
}
}
}
}
main.d import mygreeting;
int main() {
MyGreeting g = new MyGreeting();
g.setName("山田");
g.setClock(7);
printfln(g.getGreeting());
g.setClock(14);
printfln(g.getGreeting());
g.setClock(21);
printfln(g.getGreeting());
return 0;
}
private void printfln(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))) ~ "\n");
}
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(MyGreeting)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |
共通クラス
|
Proxyパターンを使用しない例 MyGreeting.pas unit UnitMyGreeting;
interface
uses
UnitGreetingOfEncounter;
type
MyGreeting = class(GreetingOfEncounter)
private
var name:string;
public
procedure setName(name:string);
function getGreeting():string;
end;
implementation
procedure MyGreeting.setName(name:string);
begin
self.name := name;
end;
function MyGreeting.getGreeting():string;
begin
Result := name + 'さん、' + inherited getGreeting();
end;
end.
Main.dpr program ProxyNon;
uses
System.SysUtils,
UnitIGreeting,
UnitGreetingOfEncounter,
UnitMyGreeting;
var g:MyGreeting;
begin
g := MyGreeting.Create();
g.setName('山田');
g.setClock(7);
Writeln(g.getGreeting());
g.setClock(14);
Writeln(g.getGreeting());
g.setClock(21);
Writeln(g.getGreeting());
g.Free;
end.
|
Proxyパターンを使用した例 MyGreeting.pas unit Main;
interface
uses
UnitIGreeting,
UnitGreetingOfEncounter;
type
MyGreeting = class
private
var name:string;
var hour:integer;
var real:IGreeting;
constructor Create(); overload;
public
procedure setName(name:string);
procedure setClock(hour:integer);
function getGreeting():string;
procedure realize();
end;
implementation
constructor MyGreeting.Create();
begin
end;
procedure MyGreeting.setName(name:string);
begin
self.name := name;
end;
procedure MyGreeting.setClock(hour:integer);
begin
if real <> nil then begin
real.setClock(hour);
end;
self.hour := hour;
end;
function MyGreeting.getGreeting():string;
begin
realize();
real.setClock(hour);
Result := name + 'さん、' + real.getGreeting();
end;
procedure MyGreeting.realize();
begin
if real = nil then begin
real := GreetingOfEncounter.Create()
end;
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitIGreeting,
UnitGreetingOfEncounter,
UnitMyGreeting;
var g:MyGreeting;
begin
g := MyGreeting.Create();
g.setName('山田');
g.setClock(7);
Writeln(g.getGreeting());
g.setClock(14);
Writeln(g.getGreeting());
g.setClock(21);
Writeln(g.getGreeting());
g.Free;
end.
|
|
この例では、時刻によって適切な挨拶を返す GreetingOfEncounter というクラスを継承して、MyGreeting を作成しています。 しかし、これでは、MyGreeting のインスタンスを生成したときに、 GreetingOfEncounter のインスタンスも生成されてしまいます。通常は、それでもまったく問題ありませんが、setName や setClock はするけれど、meeting するかどうかわからない場合はどうでしょう。 例えば、「あっ、山田さんだ。」「今、7時だ。」「挨拶しようとしたけど行っちゃった。」せっかく生成したインスタンスが無駄になってしまいます。 もし、GreetingOfEncounter のインスタンス生成に非常に時間が掛かる、メモリをたくさん使うなどの場合に、無駄が顕著になります。 |
Proxyパターンでは、MyGreeting のインスタンスは生成しますが、GreetingOfEncounter のインスタンス生成は、meeting が呼ばれて(その中から realize が呼ばれて)からです。これだと、 setName や setClock はしたけれど、meeting しなかったという場合でも、無駄はありません。 また、 GreetingOfEncounter というクラスを指定しているのは、利用者のクラス(MyGreeting)です。出会いの挨拶ではなく、別れの挨拶にしようと思ったとしても、利用者のクラスを書き換えるだけですみます。( GreetingOfEncounter を GreetingByParting にする) Proxyパターンでない場合は、 MyGreeting という別のクラスを書き換えなければなりません。 |