Mediatorパターン
オブジェクトの間の調整を行いながら処理をすすめる
Mediator とは、英語で「仲裁人、調停者」を意味する単語です。Mediator パターンとは、多数のオブジェクトの間の調整を行いながら処理をすすめる必要が ある場合に利用すると威力を発揮するパターンです。
例えば、システムの設計書などの資料を関係者が好き勝手に書き換えたとしたらどうなるでしょう?各自が、銘々に判断して、自分の都合の良いように変更する。こんな状態で、プロジェクト開発をうまく乗り切ることができるでしょうか?いくら皆が一所懸命システムをより良くしようとしたとしても、既存部分と整合性がとれなくなったり、システム仕様がむやみに膨らんでいくに違いありません。
そこで、仲裁人である「Mediator」の登場です。Mediator は、システムの進行状況を見渡し、変更の要不要を判断した上で、「許可」や「不可」の指示を出します。全てのプロジェクトメンバーは、Mediator の指示通りに変更をしたり止めたりするわけです。
Mediator パターンは、複数のオブジェクト間の調整をするために、各オブジェクトからの問い合わせを受け、適宜判断を行い指示を出す「仲裁人」の役割を果たすクラスを利用するパターンです。
Mediator パターンは、入力インタフェースなどに利用することができます。例えば、『複雑に絡み合ったある条件を満たさなければ「有効」にならないボタン』なんてものを作成したいときなどです。
「ラジオボタン Aが選択されている状態で、テキストボックスに入力がある場合」もしくは、「ラジオボタンB が選択されている状態で、チェックボックス C もしくは D にチェックが入っている場合」に「有効」になるボタンは、「ラジオボタン A」がチェックされたときに、「テキストボックスに入力があるか」を検証したり、ラジオボタン B が選択されたときに「チェックボックス C もしくは D がチェックされているか」を検証するようなプログラムにしていると、チェックボックス C にチェックが入れられたときや、チェックボックス D のチェックがはずされたときなども検証する必要があるプログラムになります。条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。
例えば、互いに通信しあうインスタンスの数が、2個ならば通信経路は2本ですが、これが3個になれば6本、4個になると12本に増え、5個になると20本、6個になると30本にもなります。
インスタンスの数が少ないときには問題は大きくありませんが、最初の設計のままどんどんインスタンスを増やしていくと、いずれ破綻をきたすことになります。
Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、「ボタン」を示すオブジェクトに、「有効」「無効」を伝えるような設計になり、管理が比較的楽になります。
つまり、各々が勝手に機能を呼び合うのでなく、必ず媒介者(仲人)を通して通信するようにしなさい。個々に勝手に通信先と話をせず、仲介人に通知先を判断してもらうようにしておきなさい、ということです。
Mediator パターンとは、オブジェクト間のやりとりそのものをカプセル化してクラスにしてしまったものです。このことによってオブジェクト間のやりとりに秩序ができ、メンテナンスしやすいものになります。
ただし、Mediator パターンは、オブジェクト指向の原則をはずしています。オブジェクト指向の面からいえば、オブジェクトはカプセル化されているべきであり、オブジェクトの変更が他のオブジェクトに影響を与えないようにすべきです。
しかし、Mediator パターンは、他のオブジェクト間のやりとりを Mediator 自身の中に持っていますので、他のオブジェクトの変更をもろに受けることになります。例えば、ひとつのオブジェクトを削除すれば、それとのやりとりも削除されなければならないからです。
例題
sw1、sw2、sw3 は 0.1秒ごとに状態の変わる可能性があります。そして、そのスイッチで次のような回路を作成しました。
電球の状態を表しなさい。
┌─SW1──SW2─┐
┌┤ ├─┐
│└────SW3───┘ 電球
│ │
└────電池電池─────┘
実行結果 (一例)
|
Mediatorパターンを使用しない例 Switch.java public class Switch extends Thread {
private Circuit circuit;
private boolean status = true; // スイッチ(閉)
private boolean run = true;
private int interval = 0;
private void actionPerformed() {
double d = Math.random();
boolean s = d > 0.5;
if (status != s) {
status = s;
if (circuit.sw[2].getStatus() == true)
circuit.lightOn(); // 点灯
else if (circuit.sw[0].getStatus() == false)
circuit.lightOff(); // 消灯
else if (circuit.sw[1].getStatus() == false)
circuit.lightOff(); // 消灯
else
circuit.lightOn(); // 点灯
}
}
protected void start(int n) {
interval = n + 500;
start();
}
public void run() {
while(run) {
actionPerformed();
try {
Thread.sleep(interval);
}
catch(Exception x) {}
}
}
protected void stop_() {
run = false;
}
private boolean getStatus() {
return status;
}
protected void setCircuit(Circuit circuit) {
this.circuit = circuit;
}
}
Circuit.java public class Circuit {
protected Switch[] sw;
private int n = 0;
private boolean status = true;
public Circuit() {
sw = new Switch[3];
for (int i = 0; i < 3; i++)
{
sw[i] = new Switch();
sw[i].setCircuit(this);
}
}
protected void lightOn() {
System.out.print("○"); // 点灯
}
protected void lightOff() {
System.out.print("●"); // 消灯
if (++n >= 5) // 5回消えたら終わり
stop();
}
public void start() {
Random rnd = new Random();
for (int i = 0; i < 3; i++)
{
int intResult = rnd.nextInt(5) + 1; // 1~5の乱数を取得
sw[i].start(100 * intResult);
}
}
public void stop() {
for (int i = 0; i < 3; i++)
{
sw[i].stop_();
}
status = false;
}
public boolean getStatus() { return status; }
}
Main.java public class Main {
public static void main(String[] args) throws Exception {
Circuit circuit = new Circuit();
circuit.start();
while(true) {
Thread.sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
}
}
|
Mediatorパターンを使用した例 Colleague.java public class Colleague extends Thread {
protected IMediator mediator;
public void setMediator(IMediator mediator) {
this.mediator = mediator;
}
}
Switch.java public class Switch extends Colleague {
private boolean status = true; // スイッチ(閉)
private boolean run = true;
private int interval = 0;
private void actionPerformed() {
double d = Math.random();
boolean s = d > 0.5;
if (status != s) { // 状態が変わったら
status = s;
mediator.colleagueChanged(); // 通知
}
}
protected void start(int n) {
interval = n + 500;
start();
}
public void run() {
while(run) {
actionPerformed();
try {
Thread.sleep(interval);
}
catch(Exception x) {}
}
}
protected void stop_() {
run = false;
}
protected boolean getStatus() {
return status;
}
}
IMediator.java public interface IMediator {
void colleagueChanged();
}
Circuit.java public class Circuit implements IMediator {
public Switch[] sw;
private int n = 0;
private boolean status = true;
public Circuit() {
sw = new Switch[3];
for (int i = 0; i < 3; i++)
{
sw[i] = new Switch();
sw[i].setMediator(this);
}
}
public void colleagueChanged() {
if (sw[2].getStatus() == true)
lightOn(); // 点灯
else if (sw[0].getStatus() == false)
lightOff(); // 消灯
else if (sw[1].getStatus() == false)
lightOff(); // 消灯
else
lightOn(); // 点灯
}
private void lightOn() {
System.out.print("○"); // 点灯
}
private void lightOff() {
System.out.print("●"); // 消灯
if (++n >= 5) // 5回消えたら終わり
stop();
}
public void start() {
Random rnd = new Random();
for (int i = 0; i < 3; i++)
{
sw[i].start(100 * (rnd.nextInt(5) + 1));
}
}
public void stop() {
for (int i = 0; i < 3; i++)
{
sw[i].stop_();
}
status = false;
}
public boolean getStatus() { return status; }
}
Main.java public class Main {
public static void main(String[] args) throws Exception {
Circuit circuit = new Circuit();
circuit.start();
while(true) {
Thread.sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
}
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 switch.h #include <windows.h>
#include "mmsystem.h"
#pragma comment(lib,"winmm.lib")
#include "circuit.h"
class Circuit;
class Switch
{
private:
Circuit* circuit;
MMRESULT timerID;
bool status = true; // スイッチ(閉)
static void CALLBACK actionPerformed(UINT, UINT, DWORD, DWORD, DWORD);
bool getStatus(void);
public:
Switch(void);
virtual ~Switch(void);
void start(int);
void stop(void);
void setCircuit(Circuit*);
}; switch.cpp #include <cstdlib> // rand, srand使用
#include <ctime> // time使用
#include "Switch.h"
Switch::Switch(void) {}
Switch::~Switch(void) {}
void CALLBACK Switch::actionPerformed(UINT uTimerID,
UINT uMsg, DWORD dwUser,
DWORD dummy1, DWORD dummy2) {
srand((unsigned) time(NULL));
bool s = (rand() % 2) > 0;
Switch* me = (Switch*)dwUser;
if (me->status != s) {
me->status = s;
if (me->circuit->sw[2]->getStatus() == true)
me->circuit->lightOn(); // 点灯
else if (me->circuit->sw[0]->getStatus() == false)
me->circuit->lightOff(); // 消灯
else if (me->circuit->sw[1]->getStatus() == false)
me->circuit->lightOff(); // 消灯
else
me->circuit->lightOn(); // 点灯
}
}
void Switch::start(int n) {
timerID = timeSetEvent(500 + n, // 間隔[ms]
0, // 分解能
actionPerformed, // 割り込み関数
(DWORD)this, // ユーザーパラメータ
TIME_PERIODIC | TIME_CALLBACK_FUNCTION // 動作フラグ
);
}
void Switch::stop(void) { // タイマー割込関数の登録抹消
timeKillEvent( timerID );
}
bool Switch::getStatus(void) { return status; }
void Switch::setCircuit(Circuit* circuit) {
this->circuit = circuit;
}
Circuit.h #include "Switch.h"
class Switch; // 循環参照の時、クラスの存在を宣言する
class Circuit
{
private:
int n = 0;
bool status = true;
public:
Switch** sw; // 循環参照の時、ポインタのみ可
public:
Circuit(void);
virtual ~Circuit(void);
void lightOn(void);
void lightOff(void);
void start(void);
void stop(void);
bool getStatus(void);
}; Circuit.cpp #include <iostream>
using namespace std;
#include "Circuit.h"
#include <cstdlib> // rand, srand使用
#include <ctime> // time使用
Circuit::Circuit(void) {
sw = new Switch*[3];
srand((unsigned) time(NULL));
for (int i = 0 ; i < 3 ; i++) {
sw[i] = new Switch(this);
sw[i]->setCircuit(this);
}
}
Circuit::~Circuit(void) {
for (int i = 0 ; i < 3 ; i++)
delete sw[i];
}
void Circuit::lightOn(void) {
cout << "○"; // 点灯
}
void Circuit::lightOff(void) {
cout << "●"; // 消灯
if (++n >= 5) // 5回消えたら終わり
stop();
}
void Circuit::start(void) {
for (int i = 0 ; i < 3 ; i++)
sw[i]->start(100 * (rand() % 5 + 1));
}
void Circuit::stop(void) {
for (int i = 0 ; i < 3 ; i++)
sw[i]->stop();
status = false;
}
bool Circuit::getStatus(void) { return status; } main.cpp #include "Circuit.h"
int main() {
Circuit circuit;
circuit.start();
while(true) {
Sleep(1000);
if (c.getStatus() == false) break;
}
circuit.stop();
return 0;
}
|
Mediatorパターンを使用した例 Colleague.h #include "IMediator.h"
class Colleague
{
protected:
IMediator* mediator;
public:
Colleague();
virtual ~Colleague();
void setMediator(IMediator* mediator);
}; Colleague.cpp #include "stdafx.h"
#include "Colleague.h"
Colleague::Colleague() {}
Colleague::~Colleague() {}
void Colleague::setMediator(IMediator* mediator) {
this->mediator = mediator;
} Switch.h #include <windows.h>
#include "mmsystem.h"
#pragma comment(lib,"winmm.lib")
#include "Colleague.h"
class IMediator;
class Switch : public Colleague
{
private:
MMRESULT timerID;
bool status; // スイッチ(閉)
static void CALLBACK actionPerformed(UINT, UINT, DWORD, DWORD, DWORD);
public:
Switch(void);
virtual ~Switch(void);
void start(int);
void stop(void);
bool getStatus(void);
}; Switch.cpp #include <cstdlib> // rand, srand使用
#include <ctime> // time使用
#include "Switch.h"
Switch::Switch(void) {}
Switch::~Switch(void) {}
void CALLBACK Switch::actionPerformed(UINT uTimerID,
UINT uMsg, DWORD dwUser,
DWORD dummy1, DWORD dummy2) {
srand((unsigned) time(NULL));
bool s = (rand() % 2) > 0;
Switch* me = (Switch*)dwUser;
if (me->status != s) {
me->status = s;
me->mediator->colleagueChanged(); // 通知
}
}
void Switch::start(int n) {
timerID = timeSetEvent(500 + n, // 間隔[ms]
0, // 分解能
actionPerformed, // 割り込み関数
(DWORD)this, // ユーザーパラメータ
TIME_PERIODIC | TIME_CALLBACK_FUNCTION // 動作フラグ
}
void Switch::stop(void) { // タイマー割り込み関数の登録抹消
timeKillEvent( timerID );
}
bool Switch::getStatus(void) { return status; }
IMediator.h class IMediator
{
public:
IMediator();
virtual ~IMediator();
virtual void colleagueChanged() = 0;
}; IMediator.cpp #include "stdafx.h"
#include "IMediator.h"
IMediator::IMediator() {}
IMediator::~IMediator() {}
Circuit.h #include "IMediator.h"
class Switch; // 循環参照の時、クラスの存在を宣言する
class Circuit : public IMediator
{
private:
int n = 0;
bool status = true;
Switch** sw; // 循環参照の時、ポインタのみ可
void colleagueChanged(void);
void lightOn(void);
void lightOff(void);
public:
Circuit(void);
virtual ~Circuit(void);
void start(void);
void stop(void);
bool getStatus(void);
}; Circuit.cpp #include <iostream>
using namespace std;
#include <cstdlib> // rand, srand使用
#include <ctime> // time使用
#include "Circuit.h"
#include "Switch.h"
Circuit::Circuit(void) {
sw = new Switch*[3];
for (int i = 0 ; i < 3 ; i++) {
sw[i] = new Switch(this);
sw[i]->setMediator(this);
}
}
Circuit::~Circuit(void) {
for (int i = 0 ; i < 3 ; i++) {
delete sw[i];
}
void Circuit::colleagueChanged(void) {
if (sw[2]->getStatus() == true)
lightOn(); // 点灯
else if (sw[0]->getStatus() == false)
lightOff(); // 消灯
else if (sw[1]->getStatus() == false)
lightOff(); // 消灯
else
lightOn(); // 点灯
}
void Circuit::lightOn(void) {
cout << "○"; // 点灯
}
void Circuit::lightOff(void) {
cout << "●"; // 消灯
if (++n >= 5) stop(); // 5回消えたら終わり
}
void Circuit::start(void) {
srand((unsigned) time(NULL));
for (int i = 0 ; i < 3 ; i++) {
sw[i]->start(100 * (rand() % 5 + 1));
}
}
void Circuit::stop(void) {
for (int i = 0 ; i < 3 ; i++) {
sw[i]->stop();
status = false;
}
bool Circuit::getStatus(void) {
return status;
} main.cpp #include <windows.h>
#include "Circuit.h"
int main() {
Circuit circuit;
circuit.start();
while(true) {
Sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
return 0;
}
|
|
スイッチは1秒未満ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 この例では、Circuit が、Mediator の役割を果たします。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを増やしたり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、回路の改造を吸収してしまえば、スイッチや電池などのクラスの改修は不要になります。 オブジェクト指向プログラミングの成功の秘訣として「できるだけオブジェクト間の関連を少なくする」ということがあります。Mediatorパターンを採用することで、オブジェクト間の関連の数を少なくできます。相互に関連を持っていれば、その関連の数は、オブジェクトが4つなら6本ですし、オブジェクトが5つなら10本ですが、 Mediatorパターンではオブジェクトが4つなら4本、5つなら5本で済みます。 |
|
Mediatorパターンを使用しない例 Switch.cs class Switch
{
private Circuit circuit;
private bool status = true;
private bool run = true;
private void ActionPerformed()
{
double d = (new Random()).NextDouble();
bool s = d > 0.5;
if (status != s) // 状態が変わったら
{
status = s; // 他のスイッチを調べる
if (circuit.sw[2].GetStatus() == true)
{
circuit.LightOn(); // 点灯
}
else if (circuit.sw[0].GetStatus() == false)
{
circuit.LightOff(); // 消灯
}
else if (circuit.sw[1].GetStatus() == false)
{
circuit.LightOff(); // 消灯
}
else
{
circuit.LightOn(); // 点灯
}
}
}
internal void Start(Object interval)
{
int.TryParse((string)interval, out int n);
while (run)
{
ActionPerformed();
System.Threading.Thread.Sleep(500 + n);
}
}
internal void Stop()
{
run = false;
}
private bool GetStatus()
{
return status;
}
internal void SetCircuit(Circuit circuit)
{
this.circuit = circuit;
}
}
Circuit.cs class Circuit
{
public Switch[] sw;
private int n = 0;
private bool status = true;
public Circuit()
{
sw = new Switch[3];
for (int i = 0; i < 3; i++)
{
sw[i] = new Switch();
sw[i].SetCircuit(this);
}
}
internal void LightOn()
{
Console.Write("○"); // 点灯
}
internal void LightOff()
{
Console.Write("●"); // 消灯
if (++n >= 5)
{
Stop(); // 5回消えたら終わり
}
}
public void Start()
{
Thread[] thread = new Thread[3];
Random rnd = new System.Random(); // インスタンスを生成
for (int i = 0; i < 3; i++)
{
int intResult = rnd.Next(5) + 1; // 1~6の乱数を取得
thread[i] = new Thread(new ParameterizedThreadStart(sw[i].Start));
thread[i].Start("" + (100 * intResult)); // スレッド開始
}
}
public void Stop()
{
for (int i = 0; i < 3; i++)
{
sw[i].Stop();
}
status = false;
}
public bool getStatus() { return status; }
}
Program.cs class Program
{
static void Main(string[] args)
{
Circuit circuit = new Circuit();
circuit.Start();
while(true)
{
Thread.Sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.Stop();
}
}
|
Mediatorパターンを使用した例 Colleague.cs class Colleague
{
protected IMediator mediator;
public void SetMediator(IMediator mediator)
{
this.mediator = mediator;
}
} Switch.cs class Switch : Colleague
{
private bool status = true;
private bool run = true;
private void ActionPerformed()
{
double d = (new Random()).NextDouble();
bool s = d > 0.5;
if (status != s) // 状態が変わったら
{
status = s;
mediator.ColleagueChanged(); // 通知
}
}
internal void Start(Object interval)
{
int.TryParse((string)interval, out int n);
while (run)
{
ActionPerformed();
System.Threading.Thread.Sleep(500 + n);
}
}
internal void Stop()
{
run = false;
}
internal bool GetStatus()
{
return status;
}
}
IMediator.cs interface IMediator
{
void ColleagueChanged();
}
Circuit.cs class Circuit : IMediator
{
public Switch[] sw;
private int n = 0;
private bool status = true;
public Circuit()
{
sw = new Switch[3];
for (int i = 0; i < 3; i++)
{
sw[i] = new Switch();
sw[i].SetMediator(this);
}
}
private void ColleagueChanged()
{
if (sw[2].GetStatus() == true)
{
LightOn(); // 点灯
}
else if (sw[0].GetStatus() == false)
{
LightOff(); // 消灯
}
else if (sw[1].GetStatus() == false)
{
LightOff(); // 消灯
}
else
{
LightOn(); // 点灯
}
}
private void LightOn()
{
Console.Write("○"); // 点灯
}
private void LightOff()
{
Console.Write("●"); // 消灯
if (++n >= 5)
{
Stop(); // 5回消えたら終わり
}
}
public void Start()
{
Thread[] thread = new Thread[3];
Random rnd = new System.Random(); // インスタンスを生成
for (int i = 0; i < 3; i++)
{
int intResult = rnd.Next(5) + 1; // 0~9の乱数を取得
thread[i] = new Thread(new ParameterizedThreadStart(sw[i].Start));
thread[i].Start("" + (100 * intResult)); // スレッド開始
}
}
public void Stop()
{
for (int i = 0; i < 3; i++)
{
sw[i].Stop();
}
status = false;
}
public bool GetStatus() { return status; }
}
Program.cs class Program
{
static void Main(string[] args)
{
Circuit circuit = new Circuit();
circuit.Start();
while (true)
{
Thread.Sleep(1000);
if (circuit.GetStatus() == false) break;
}
circuit.Stop();
}
}
|
|
スイッチは1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの ColleagueChanged() メソッドを呼び出します。ColleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.vb Public Class Switch
Private circuit As Circuit
Private status As Boolean = True
Private run As Boolean = True
Private Sub ActionPerformed()
Dim d As Double = (New Random()).NextDouble()
Dim s As Boolean = d > 0.5
If status <> s Then ' 状態が変わったら
status = s ' 他のスイッチを調べる
If circuit.sw(2).GetStatus() = True Then
circuit.LightOn() ' 点灯
ElseIf circuit.sw(0).GetStatus() = False Then
circuit.LightOff() ' 消灯
ElseIf circuit.sw(1).GetStatus() = False Then
circuit.LightOff() ' 消灯
Else
circuit.LightOn() ' 点灯
End If
End If
End Sub
Friend Sub StartRun(interval As Integer)
Dim n As Integer
Int32.TryParse(interval, n)
While run
ActionPerformed()
System.Threading.Thread.Sleep(500 + n)
End While
End Sub
Friend Sub StopRun()
run = False
End Sub
Private Function GetStatus() As Boolean
Return status
End Function
Friend Sub SetCircuit(ByVal circuit As Circuit)
Me.circuit = circuit
End Sub
End Class
Circuit.vb Imports System.Threading
Public Class Circuit
Friend sw As Switch()
Private n As Integer = 0
Private status As Boolean = True
Public Sub New()
sw = New Switch(3) {}
For i As Integer = 0 To 2
sw(i) = New Switch()
sw(i).SetCircuit(Me)
Next
End Sub
Friend Sub LightOn()
Console.Write("○") ' 点灯
End Sub
Friend Sub LightOff()
Console.Write("●") ' 消灯
n += 1 : If n >= 5 Then StopRun() ' 5回消えたら終わり
End Sub
Public Sub Start()
Dim thread As Thread() = New Thread(3) {}
Dim rnd As Random = New System.Random()
For i As Integer = 0 To 2
Dim intResult As Integer = rnd.Next(5) + 1 ' 1~6の乱数
thread(i) = New Thread(New ParameterizedThreadStart (AddressOf sw(i).StartRun))
thread(i).Start((100 * intResult)) ' スレッド開始
Next
End Sub
Public Sub StopRun()
For i As Integer = 0 To 2
sw(i).StopRun()
Next
status = False
End Sub
Public Function GetStatus()
Return status
End Function
End Class
Program.vb Module Main
Sub Main()
Dim circuit As Circuit = New Circuit()
circuit.Start()
While True
Threading.Thread.Sleep(1000)
If circuit.GetStatus() = False Then Exit While
End While
End Sub
End Module
|
Mediatorパターンを使用した例 Colleague.vb Public Class Colleague
Protected mediator As IMediator
Public Sub SetMediator(ByVal mediator As IMediator)
Me.mediator = mediator
End Sub
End Class
Switch.vb Public Class Switch
Inherits Colleague
Private status As Boolean = True
Private run As Boolean = True
Private Sub ActionPerformed()
Dim d As Double = Rnd()
Dim s As Boolean = d > 0.5
If status <> s Then ' 状態が変わったら
status = s
mediator.ColleagueChanged() ' 通知
End If
End Sub
Friend Sub StartRun(interval As Integer)
Dim n As Integer
Int32.TryParse(interval, n)
While run
ActionPerformed()
System.Threading.Thread.Sleep(500 + n)
End While
End Sub
Friend Sub StopRun()
run = False
End Sub
Friend Function GetStatus() As Boolean
Return status
End Function
End Class
IMediator.vb Public Interface IMediator
Sub ColleagueChanged()
End Interface
Circuit.vb Imports System.Threading
Public Class Circuit
Implements IMediator
Friend sw As Switch()
Private n As Integer = 0
Private status As Boolean = True
Public Sub New()
sw = New Switch(3) {}
For i As Integer = 0 To 2
sw(i) = New Switch()
sw(i).SetCircuit(Me)
Next
End Sub
Public Sub ColleagueChanged() Implements IMediator.ColleagueChanged
If sw(2).GetStatus() = True Then
LightOn() ' 点灯
ElseIf sw(0).getStatus() = False Then
LightOff() ' 消灯
ElseIf sw(1).getStatus() = False Then
LightOff() ' 消灯
Else
LightOn() ' 点灯
End If
End Sub
Private Sub LightOn()
Console.Write("○") ' 点灯
End Sub
Private Sub LightOff()
Console.Write("●") ' 消灯
n += 1 : If n >= 5 Then StopRun() ' 5回消えたら終わり
End Sub
Public Sub Start()
Dim thread As Thread() = New Thread(3) {}
Dim rnd As Random = New System.Random()
For i As Integer = 0 To 2
Dim intResult As Integer = rnd.Next(5) + 1 ' 1~6の乱数
thread(i) = New Thread(New ParameterizedThreadStart (AddressOf sw(i).StartRun))
thread(i).Start((100 * intResult)) ' スレッド開始
Next
End Sub
Public Sub StopRun()
For i As Integer = 0 To 2
sw(i).StopRun()
Next
status = False
End Sub
Public Function GetStatus()
Return status
End Function
End Class
Program.vb Module Main
Sub Main()
Dim circuit As Circuit = New Circuit()
circuit.Start()
While True
Threading.Thread.Sleep(1000)
If circuit.GetStatus() = False Then Exit While
End While
End Sub
End Module
|
|
スイッチは1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの ColleagueChanged() メソッドを呼び出します。ColleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.js module.exports = class Switch {
constructor() {
this.status = true; // スイッチ(閉)
this.run = true;
this.interval = 0;
}
actionPerformed() {
let d = Math.random();
let s = d > 0.5;
if (this.status != s) {
this.status = s;
if (this.circuit.sw[2].getStatus() == true)
this.circuit.lightOn(); // 点灯
else if (this.circuit.sw[0].getStatus() == false)
this.circuit.lightOff(); // 消灯
else if (this.circuit.sw[1].getStatus() == false)
this.circuit.lightOff(); // 消灯
else
this.circuit.lightOn(); // 点灯
}
}
async start(n) {
this.interval = n + 500;
while(this.run) {
this.actionPerformed();
await sleep(this.interval);
}
}
stop() {
this.run = false;
}
getStatus() {
return this.status;
}
setCircuit(circuit) {
this.circuit = circuit;
}
}
function sleep(msec) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
Circuit.pm const Switch = require("./Switch.js");
module.exports = class Circuit {
constructor() {
this.n = 0;
this.status = true;
this.sw = [new Switch(), new Switch(), new Switch()];
for (let i = 0; i < 3; i++)
{
this.sw[i].setCircuit(this);
}
}
lightOn() {
process.stdout.write("○"); // 点灯
}
lightOff() {
process.stdout.write("●"); // 消灯
if (++this.n >= 5) // 5回消えたら終わり
this.stop();
}
start() {
for (let i = 0; i < 3; i++)
{
let intResult = Math.random() * 5 + 1; // 0~4の乱数を取得
this.sw[i].start(100 * intResult);
}
}
stop() {
for (let i = 0; i < 3; i++)
{
this.sw[i].stop();
}
this.status = false;
}
getStatus() { return this.status; }
}
Main.js const Circuit = require("./Circuit.js");
function sleep(msec) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
async function main() {
let circuit = new Circuit();
circuit.start();
while(true) {
await sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
}
main();
|
Mediatorパターンを使用した例 Colleague.js module.exports = class Colleague {
setMediator(mediator) {
this.mediator = mediator;
}
}
Switch.java const Colleague = require("./Colleague.js");
module.exports = class Switch extends Colleague {
constructor() {
super();
this.status = true; // スイッチ(閉)
this.run = true;
this.interval = 0;
}
async start(n) {
this.interval = n + 500;
while(this.run) {
let s = Math.random() > 0.5;
if (this.status != s) { // 状態が変わったら
this.status = s;
this.mediator.colleagueChanged(); // 通知
}
await sleep(this.interval);
}
}
stop() {
this.run = false;
}
getStatus() {
return this.status;
}
}
function sleep(msec) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
Circuit.js const Switch = require("./Switch.js");
module.exports = class Circuit {
constructor() {
this.n = 0;
this.status = true;
this.sw = [new Switch(), new Switch(), new Switch()];
for (let i = 0; i < 3; i++)
{
this.sw[i].setMediator(this);
}
}
colleagueChanged() {
if (this.sw[2].getStatus() == true)
this.lightOn(); // 点灯
else if (this.sw[0].getStatus() == false)
this.lightOff(); // 消灯
else if (this.sw[1].getStatus() == false)
this.lightOff(); // 消灯
else
this.lightOn(); // 点灯
}
lightOn() {
process.stdout.write("○"); // 点灯
}
lightOff() {
process.stdout.write("●"); // 消灯
if (++this.n >= 5) // 5回消えたら終わり
this.stop();
}
start() {
for (let i = 0; i < 3; i++)
{
this.sw[i].start(100 * (Math.random() * 5 + 1));
}
}
stop() {
for (let i = 0; i < 3; i++)
{
this.sw[i].stop();
}
this.status = false;
}
getStatus() { return this.status; }
}
Main.js const Circuit = require("./Circuit.js");
function sleep(msec) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
async function main() {
let circuit = new Circuit();
circuit.start();
while(true) {
await sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
}
main();
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.pm package Switch {
use Time::HiRes 'usleep';
use threads;
use threads::shared;
$| = 1;
my $swList : shared = ( &share([]) ); # 同じインスタンスのスレッド間で共有
sub new {
my ($class, $no) = @_;
my $this:shared = &share({}) ;
$this->{status} = "true";
$this->{run} = "true";
$this->{no} = $no;
$this->{interval} = 0;
bless $this, $class;
$swList->[$no] = $this;
return bless $this;
}
sub actionPerformed {
my ($this) = @_;
my $d = rand(10);
my $s = $d > 5 ? "true" : "false";
if ($this->{status} ne $s) {
$this->{status} = $s;
if ($swList->[2]->getStatus() eq "true") {
$this->{circuit}->lightOn(); # 点灯
}
elsif ($swList->[0]->getStatus() eq "false") {
$this->{circuit}->lightOff(); # 消灯
}
elsif ($swList->[1]->getStatus() eq "false") {
$this->{circuit}->lightOff(); # 消灯
}
else {
$this->{circuit}->lightOn(); # 点灯
}
}
}
sub start {
my ($this, $n, $circuit) = @_;
$this->{interval} = ($n + 5) * 100;
$this->{circuit} = $circuit;
while($this->{run} eq "true") {
$this->actionPerformed();
usleep($this->{interval} * 1000);
threads->yield();
}
}
sub stop {
my ($this) = @_;
$this->{run} = "false";
}
sub getStatus {
my ($this) = @_;
return $this->{status};
}
}
1;
Circuit.pm package Circuit {
use Switch;
use threads;
use threads::shared;
use Time::HiRes 'usleep';
my @swList = ();
my $circuit;
sub new {
my ($class) = @_;
my $this = { n => 0, status => "true" };
$circuit = share($this);
return bless $this, $class;
}
sub lightOn {
print "○"; # 点灯
}
sub lightOff {
my ($this) = @_;
print "●"; # 消灯
if (++$this->{n} >= 5) {
$this->stop();
}
}
sub start {
my ($this) = @_;
for my $i (0 .. 2) {
my $sw = new Switch($i);
push(@swList, $sw);
}
for my $i (0 .. 2) {
my $t = threads->create(\&startSwitch, $i);
push(@thrList, $t);
}
foreach my $t (@thrList) {
$t->join();
}
}
sub startSwitch {
my ($i) = @_;
my $intResult = int(rand(5)) + 1; # 0~4の乱数を取得
$swList[$i]->start($intResult, $circuit);
}
sub stop {
my ($this) = @_;
foreach my $sw ( @swList ) {
$sw->stop();
}
$this->{status} = "false";
}
sub getStatus {
my ($this) = @_;
return $sw->{status};
}
}
1;
Main.pl use lib qw(./);
use Circuit;
use Time::HiRes 'usleep';
my $circuit = new Circuit();
$circuit->start();
while(1) {
usleep(1000 * 1000);
last if ($circuit->getStatus() eq "false");
}
|
Mediatorパターンを使用した例 Colleague.pm package Colleague {
sub setMediator {
my ($this, $mediator) = @_;
$this->{mediator} = $mediator;
}
}
1;
Switch.pm package Switch {
use Time::HiRes 'usleep';
use threads;
use threads::shared;
use base qw(Colleague);
sub new {
my ($class, $no) = @_;
my $this:shared = &share({}) ;
$this->{status} = "true";
$this->{run} = "true";
$this->{no} = $no;
$this->{interval} = 0;
bless $this, $class;
$swList->[$no] = $this;
return $this;
}
sub start {
my ($this, $n) = @_;
$this->{interval} = ($n + 5) * 100;
while($this->{run} eq "true") {
my $d = rand(10);
my $s = $d > 5 ? "true" : "false";
if ($this->{status} ne $s) {
$this->{status} = $s;
$this->{mediator}->colleagueChanged();
usleep($this->{interval} * 1000);
threads->yield();
}
}
}
sub stop {
my ($this) = @_;
$this->{run} = "false";
}
sub getStatus {
my ($this) = @_;
return $this->{status};
}
}
1;
Circuit.js $| = 1;
package Circuit {
use Switch;
use threads;
use threads::shared;
use Time::HiRes 'usleep';
my @swList = ();
my $circuit;
sub new {
my ($class) = @_;
my $this = { n => 0, status => "true" };
$circuit = share($this);
return bless $this, $class;
}
sub colleagueChanged {
if ($swList[2]->getStatus() eq "true") {
$circuit->lightOn(); # 点灯
}
elsif ($swList[0]->getStatus() eq "false") {
$circuit->lightOff(); # 消灯
}
elsif ($swList[1]->getStatus() eq "false") {
$circuit->lightOff(); # 消灯
}
else {
$circuit->lightOn(); # 点灯
}
}
sub lightOn {
print "○"; # 点灯
}
sub lightOff {
my ($this) = @_;
print "●"; # 消灯
if (++$this->{n} >= 5) {
$this->stop();
}
}
sub start {
my ($this) = @_;
for my $i (0 .. 2) {
my $sw = new Switch($i);
push(@swList, $sw);
}
for my $i (0 .. 2) {
my $t = threads->create(\&startSwitch, $i);
push(@thrList, $t);
}
foreach my $t (@thrList) {
$t->join();
}
}
sub startSwitch {
my ($i) = @_;
my $intResult = int(rand(5)) + 1; # 0~4の乱数を取得
$swList[$i]->setMediator($circuit);
$swList[$i]->start($intResult);
}
sub stop {
my ($this) = @_;
foreach my $sw ( $swList ) {
$sw->stop();
}
$this->{status} = "false";
}
sub getStatus {
my ($this) = @_;
return $this->{status};
}
}
1;
Main.pl use lib qw(./);
use Circuit;
use Time::HiRes 'usleep';
my $circuit = new Circuit();
$circuit->start();
while(1) {
usleep(1000 * 1000);
last if ($circuit->getStatus() eq "false");
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.rb class Switch
def initialize()
@status = true # スイッチ(閉)
@run = true
@interval = 0
end
def actionPerformed()
d = rand(0..99)
s = d > 50
if @status != s then
@status = s
if @circuit.sw[2].getStatus() == true then
@circuit.lightOn() # 点灯
elsif (@circuit.sw[0].getStatus() == false then
@circuit.lightOff() # 消灯
elsif @circuit.sw[1].getStatus() == false then
@circuit.lightOff() # 消灯
else
@circuit.lightOn() # 点灯
end
end
end
def start(n)
@interval = n + 500
block = Thread.new do
begin
actionPerformed()
sleep(@interval.to_f / 1000)
end while @run
end
def stop()
@run = false
end
def getStatus()
return @status
end
def setCircuit(circuit)
@circuit = circuit
end
end
Circuit.rb require './Switch'
class Circuit
attr_reader :sw
def initialize()
@n = 0;
@status = true
@sw = [Switch.new(), Switch.new(), Switch.new()]
for i in 0..2 do
@sw[i].setCircuit(self)
end
end
def lightOn()
puts "○" # 点灯
end
def lightOff()
puts "●" # 消灯
@n += 1
if @n >= 5 then # 5回消えたら終わり
stop()
end
end
def start()
for i in 0..2 do
@sw[i].start(100 * rand(1..5))
end
end
def stop()
for i in 0..2 do
@sw[i].stop()
end
@status = false
end
def getStatus()
return @status
end
end
Main.rb require './Circuit'
circuit = Circuit.new()
circuit.start()
while(true)
sleep(1)
if (circuit.getStatus() == false then
break
end
end
circuit.stop()
|
Mediatorパターンを使用した例 Colleague.rb class Colleague
def setMediator(mediator)
@mediator = mediator
end
end
Switch.rb require './Colleague'
class Switch < Colleague
def initialize()
super()
@status = true # スイッチ(閉)
@run = true
@interval = 0
end
def start(n)
@interval = n + 500
block = Thread.new do
begin
s = rand(0..99) > 50
if @status != s then # 状態が変わったら
@status = s
@mediator.colleagueChanged() # 通知
end
sleep(@interval.to_f / 1000)
end while @run
end
end
def stop()
@run = false
end
def getStatus()
return @status
end
end
Circuit.rb require './Switch'
class Circuit
def initialize()
@n = 0
@status = true
@sw = [Switch.new(), Switch.new(), Switch.new()]
for i in 0..2 do
@sw[i].setMediator(self)
end
end
def colleagueChanged()
if @sw[2].getStatus() == true then
lightOn() # 点灯
elsif (@sw[0].getStatus() == false then
lightOff() # 消灯
elsif (@sw[1].getStatus() == false then
lightOff() # 消灯
else
lightOn() # 点灯
end
end
def lightOn()
puts "○" # 点灯
end
def lightOff()
puts "●" # 消灯
@n += 1
if @n >= 5 then # 5回消えたら終わり
stop()
end
end
def start()
for i in 0..2 do
@sw[i].start(100 * rand(1..5))
end
end
def stop()
for i in 0..2 do
@sw[i].stop()
end
@status = false
end
def getStatus()
return @status
end
end
Main require './Circuit.js'
circuit = Circuit.new()
circuit.start()
while(true)
sleep(1)
if circuit.getStatus() == false then
break
end
end
circuit.stop()
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.py import random
import threading
from time import sleep
class Switch(threading.Thread):
def __init__(self, no):
super(Switch, self).__init__()
self.status = True
self.running = True
self.no = no
self.interval = 0
def actionPerformed(self):
d = random.randint(0, 99)
s = d > 50
if self.status != s:
self.status = s
if self.circuit.sw[2].getStatus() == True:
self.circuit.lightOn() # 点灯
elif self.circuit.sw[0].getStatus() == False:
self.circuit.lightOff() # 消灯
elif self.circuit.sw[1].getStatus() == False:
self.circuit.lightOff() # 消灯
else:
self.circuit.lightOn() # 点灯
def _start(self, n):
self.interval = n + 500
self.start()
def run():
while self.running == True:
self.actionPerformed()
sleep(self.interval / 1000.0)
def stop(self):
self.running = False
def getStatus(self):
return self.status
def setCircuit(self, circuit):
self.circuit = circuit
Circuit.py import random
import threading
from time import sleep
from Switch import Switch
class Circuit:
def __init__(self):
self.n = 0
self.status = True
self.sw = []
for i in range(3):
s = Switch(i)
s.setCircuit(self)
self.sw.append(s)
def lightOn(self):
print("○", end="", flush=True) # 点灯
def lightOff():
print("●", end="", flush=True) # 消灯
self.n += 1
if self.n >= 5: # 5回消えたら終わり
self.stop()
def start():
for i in range(3):
intResult = random.randint(1, 5) # 1~5の乱数を取得
self.sw[i]._start(100 * intResult)
def stop(self):
for s in self.sw:
s.stop()
self.status = False
def getStatus(self):
return self.status
Main.py from time import sleep
from Circuit import Circuit
circuit = Circuit()
circuit.start()
while True:
sleep(1)
if circuit.getStatus() == False:
break
circuit.stop()
|
Mediatorパターンを使用した例 Colleague.py import threading
class Colleague(threading.Thread):
def __init__(self):
super(Colleague, self).__init__()
def setMediator(self, mediator):
self.mediator = mediator
Switch.py import random
from time import sleep
from Colleague import Colleague
class Switch(Colleague):
def __init__(self, no):
super(Switch, self).__init__()
self.status = True
self.running = True
self.interval = 0
def actionPerformed(self):
d = random.randint(0, 99)
s = d > 50
if self.status != s: # 状態が変わったら
self.status = s
self.mediator.colleagueChanged() # 通知
def _start(self, n):
self.interval = n + 500
self.start()
def run(self):
while self.running == True:
self.actionPerformed()
sleep(self.interval / 1000.0)
def stop(self):
self.running = False
def getStatus(self):
return self.status
IMediator.py from abc import ABCMeta, abstractmethod
class IMediator(metaclass=ABCMeta):
@abstractmethod
def colleagueChanged():
pass
Circuit.py import random
from IMediator import IMediator
from Switch import Switch
class Circuit(IMediator):
def __init__(self):
self.n = 0
self.status = True
self.sw = []
for i in range(3):
s = Switch(i)
s.setMediator(self)
self.sw.append(s)
def colleagueChanged(self):
if self.sw[2].getStatus() == True:
self.lightOn() # 点灯
elif self.sw[0].getStatus() == False:
self.lightOff() # 消灯
elif self.sw[1].getStatus() == False:
self.lightOff() # 消灯
else:
self.lightOn() # 点灯
def lightOn(self):
print("○", end="", flush=True) # 点灯
def lightOff(self):
print("●", end="", flush=True) # 消灯
self.n += 1
if self.n >= 5: # 5回消えたら終わり
self.stop()
def start(self)
for i in range(3):
intResult = random.randint(1, 5) # 1~5の乱数を取得
self.sw[i]._start(100 * intResult)
def stop(self):
for s in self.sw:
s.stop()
self.status = False
def getStatus(self):
return self.status
Main.py from time import sleep
from Circuit import Circuit
circuit = Circuit()
circuit.start()
while True:
sleep(1)
if (circuit.getStatus() == False:
break
circuit.stop()
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
Switchx インスタンスは複数のスレッドで実行されています。そして、それらから同じ Circuit インスタンスを参照しているのですが、なぜか Circuit インスタンスもスレッドの数だけ生成されてしまうようです。そのため、Circuit インスタンス内にカウンターを持っても Switchx インスタンス間で共有されません。
そこで、Circuit インスタンス内で共有メモリを生成し、その中にカウンターを持つようにしています。
|
Mediatorパターンを使用しない例 Switch.php <?php
public class Switchx extends Thread {
private $circuit;
private $status = true; // スイッチ(閉)
private $run = true;
private $interval = 0;
public function __construct() {
$this->status = true;
$this->run = true;
$this->interval = 0;
}
private function actionPerformed() {
$d = rand(1, 10);
$s = $d > 5;
if ($this->status != $s) {
$this->status = $s;
if ($this->circuit.sw[2].getStatus() == true)
$this->circuit.lightOn(); // 点灯
else if ($this->circuit.sw[0].getStatus() == false)
$this->circuit.lightOff(); // 消灯
else if ($this->circuit.sw[1].getStatus() == false)
$this->circuit.lightOff(); // 消灯
else
$this->circuit.lightOn(); // 点灯
}
}
public function start_($n) {
$this->interval = $n + 400;
$this->start();
}
public function run() {
while($this->run) {
$this->actionPerformed();
time_nanosleep(0, $this->interval * 1000 * 1000);
}
}
public function stop() {
$this->run = false;
}
private function getStatus() {
return $this->status;
}
public function setCircuit(Circuit $circuit) {
$this->circuit = $circuit;
}
}
?>
Circuit.php <?php
require_once('Switch.php');
class Circuit {
public $sw;
private $status = true;
public __construct() {
$this->sw = [new Switchx(), new Switchx(), new Switchx()];
$this->setCounter(0); // カウンターのリセット
}
public void lightOn() {
System.out.print("○"); // 点灯
}
public void lightOff() {
System.out.print("●"); // 消灯
$counter = $this->getCounter() + 1;
if ($counter >= 5) // 5回消えたら終わり
stop();
$this->setCounter($counter);
}
public void start() {
for ($i = 0; $i < count($this->sw); $i++)
{
$this->sw[$i]->setCircuit($this);
$intResult = rand(1, 5); // 1~5の乱数を取得
$this->sw[$i].start_(100 * $intResult);
}
for ($i = 0; $i < count($this->sw); $i++)
$this->sw[$i]->join();
}
}
public void stop() {
for ($i = 0; $i < count($this->sw); $i++)
{
$this->sw[$i].stop();
}
$shmid = shmop_open(0, "c", 0644, 4);
shmop_delete($shmid);
shmop_close($shmid);
$this->status = false;
}
public boolean getStatus() { return status; }
public function setCounter($val) {
$shmid = shmop_open(0, "c", 0644, 4); // 共有メモリ
shmop_write($shmid, (string)$val, 0);
}
public function getCounter() {
$shmid = shmop_open(0, "c", 0644, 4); // 共有メモリ
$data = shmop_read($shmid, 0, 1);
return (int)$data;
}
}
?>
Main.php <?php
require_once('Circuit.php');
$circuit = new Circuit();
$circuit->start();
$circuit->stop();
?>
|
Mediatorパターンを使用した例 Colleague.php <?php
class Colleague extends Thread {
protected $mediator;
public function setMediator($mediator) {
$this->mediator = $mediator;
}
}
?>
Switch.php <?php
require_once('Colleague.php');
class Switch extends Colleague {
private $status = true; // スイッチ(閉)
private $run = true;
private $interval = 0;
private function actionPerformed() {
$d = rand(1, 10);
$s = $d > 5;
if ($this->status != $s) { // 状態が変わったら
$this->status = $s;
$this->mediator->colleagueChanged(); // 通知
}
}
public function start_($n) {
$this->interval = $n + 400;
$this->start();
}
public function run() {
while($this->run) {
$this->actionPerformed();
time_nanosleep(0, $this->interval * 1000 * 1000);
}
}
public function stop() {
$this->run = false;
}
public function getStatus() {
return $this->status;
}
}
?>
IMediator.php
<?php
interface IMediator {
public function colleagueChanged();
}
?>
Circuit.php <?php
require_once('IMediator.php');
require_once('Switch.php');
class Circuit implements IMediator {
public $sw;
private $status = true;
public function __construct() {
$this->sw = [new Switchx(), new Switchx(), new Switchx()];
$this->setCounter(0); // カウンターのリセット
}
public function colleagueChanged() {
if ($this->sw[2].getStatus() == true)
lightOn(); // 点灯
else if ($this->sw[0].getStatus() == false)
lightOff(); // 消灯
else if ($this->sw[1].getStatus() == false)
lightOff(); // 消灯
else
lightOn(); // 点灯
}
private function lightOn() {
print "○"; // 点灯
}
private function lightOff() {
print "●"; // 消灯
$counter = $this->getCounter() + 1;
if ($counter >= 5) // 5回消えたら終わり
$this->stop();
$this->setCounter($counter);
}
public function start() {
for ($i = 0; i < count($this->sw); $i++) {
$this->sw[$i]->setMediator($this);
$intResult = rand(1, 5); // 1~5の乱数を取得
$this->sw[$i].start_(100 * $intResult);
}
for ($i = 0; i < count($this->sw); $i++) {
$this->sw[$i].join();
}
}
public void stop() {
for ($i = 0; i < count($this->sw); $i++) {
$this->sw[$i].stop();
}
status = false;
}
public boolean getStatus() { return status; }
public function setCounter($val) {
$shmid = shmop_open(0, "c", 0644, 4); // 共有メモリ
shmop_write($shmid, (string)$val, 0);
}
public function getCounter() {
$shmid = shmop_open(0, "c", 0644, 4); // 共有メモリ
$data = shmop_read($shmid, 0, 1);
return (int)$data;
}
}
?>
Main.php <?php
require_once('Circuit.php');
$circuit = new Circuit();
$circuit->start();
$circuit->stop();
?>
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.ts export
class Switch {
private circuit:any;
private status:boolean = true; // スイッチ(閉)
private run = true;
private interval:number = 0;
private actionPerformed():void {
let d:number = Math.random();
let s:boolean = d > 0.5;
if (this.status != s) {
this.status = s;
if (this.circuit.sw[2].getStatus() == true)
this.circuit.lightOn(); // 点灯
else if (this.circuit.sw[0].getStatus() == false)
this.circuit.lightOff(); // 消灯
else if (this.circuit.sw[1].getStatus() == false)
this.circuit.lightOff(); // 消灯
else
this.circuit.lightOn(); // 点灯
}
}
public async start(n:number):Promise<any> {
this.interval = n + 500;
while(this.run) {
this.actionPerformed();
await sleep(this.interval);
}
}
public stop():void {
this.run = false;
}
public getStatus():boolean {
return this.status;
}
public setCircuit(circuit:any):void {
this.circuit = circuit;
}
}
function sleep(msec:number) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
Circuit.ts import {Switch} from "./Switch";
export
class Circuit {
private n:number = 0;
private status:boolean = true;
private sw:Array<Switch>;
public constructor() {
sw = [new Switch(), new Switch(), new Switch()];
for (let i:number = 0; i < 3; i++)
{
sw[i].setCircuit(this);
}
}
public lightOn():void {
process.stdout.write("○"); // 点灯
}
public lightOff():void {
process.stdout.write("●"); // 消灯
if (++this.n >= 5) // 5回消えたら終わり
this.stop();
}
public start():void {
for (let i:number = 0; i < 3; i++)
{
let intResult:number = Math.random() * 5 + 1; // 1~5の乱数を取得
this.sw[i].start(100 * intResult);
}
}
public stop():void {
for (let i:number = 0; i < 3; i++)
{
this.sw[i].stop();
}
this.status = false;
}
private getStatus():boolean {
return this.status;
}
}
Main.ts import {Circuit} from "./Circuit";
function sleep(msec:number) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
async function main() {
let circuit:Circuit = new Circuit();
circuit.start();
while(true) {
await sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
}
main();
|
Mediatorパターンを使用した例 Colleague.ts export
class Colleague {
protected mediator:any;
public setMediator(mediator:any):void {
this.mediator = mediator;
}
}
Switch.ts import {Colleague} from "./Colleague";
export
class Switch extends Colleague {
private status:boolean = true; // スイッチ(閉)
private run:boolean = true;
private interval:number = 0;
public async start(n:number):Promise<void> {
this.interval = n + 500;
while(this.run) {
let s:boolean = Math.random() > 0.5;
if (this.status != s) { // 状態が変わったら
this.status = s;
this.mediator.colleagueChanged(); // 通知
}
await sleep(this.interval);
}
}
public stop() {
this.run = false;
}
public getStatus() {
return this.status;
}
}
function sleep(msec:number) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
Circuit.ts import {Switch} from "./Switch";
export
class Circuit {
private n:number = 0;
private status:boolean = true;
private sw:Array<Switch>;
public constructor() {
sw = [new Switch(), new Switch(), new Switch()];
for (i:number = 0; i < 3; i++)
{
this.sw[i].setMediator(this);
}
}
public colleagueChanged():void {
if (this.sw[2].getStatus() == true)
this.lightOn(); // 点灯
else if (this.sw[0].getStatus() == false)
this.lightOff(); // 消灯
else if (this.sw[1].getStatus() == false)
this.lightOff(); // 消灯
else
this.lightOn(); // 点灯
}
private void lightOn() {
process.stdout.write("○"); // 点灯
}
private void lightOff() {
process.stdout.write("●"); // 消灯
if (++this.n >= 5) // 5回消えたら終わり
this.stop();
}
public void start() {
for (let i:number = 0; i < 3; i++)
{
this.sw[i].start(100 * (Math.random() * 5 + 1));
}
}
public void stop() {
for (let i:number = 0; i < 3; i++)
this.sw[i].stop();
}
this.status = false;
}
public getStatus():boolean {
return this.status;
}
}
Main.ts import {Circuit} from "./Circuit";
function sleep(msec:number) {
return new Promise(function(resolve, reject) {
setTimeout(resolve, msec);
});
}
async function main() {
let circuit = new Circuit();
circuit.start();
while(true) {
await sleep(1000);
if (circuit.getStatus() == false) break;
}
circuit.stop();
}
main();
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.swift import Foundation
public class Switch {
private var circuit:Circuit!
private var status:Bool = true // スイッチ(閉)
private var run:Bool = true
private func actionPerformed() {
let s:Bool = Int.random(in: 0..<10) > 5
if status != s {
status = s
if circuit.sw[2].getStatus() == true {
circuit.lightOn() // 点灯
}
else if circuit.sw[0].getStatus() == false {
circuit.lightOff() // 消灯
}
else if circuit.sw[1].getStatus() == false {
circuit.lightOff() // 消灯
}
else {
circuit.lightOn() // 点灯
}
}
}
internal func start(_ n:UInt32) {
interval:Double = Double(n + 500) / 1000.0
while(run) {
actionPerformed()
Thread.sleep(forTimeInterval: interval)
}
}
internal func stop() {
run = false
}
internal func getStatus() -> Bool {
return status
}
internal func setCircuit(_ circuit:Circuit) {
self.circuit = circuit
}
}
Circuit.swift import Foundation
public class Circuit {
private var n:Int = 0
private var status:Bool = true
internal var sw:[Switch]
private var dispatchGroup:DispatchGroup!
private var dispatchQueue:DispatchQueue!
public init() {
sw = [Switch(), Switch(), Switch()]
for i in 0..<3 {
{
sw[i].setCircuit(self)
}
}
internal func lightOn() {
print("○", terminator:"") // 点灯
fflush(stdout)
}
internal func lightOff() {
print("●", terminator:"") // 消灯
fflush(stdout)
n += 1
if n >= 5 { // 5回消えたら終わり
stop()
}
}
public func start() {
dispatchGroup = DispatchGroup()
dispatchQueue = DispatchQueue(label: "queue", attributes: .concurrent)
for i in 0..<3 {
let intResult:UInt32 = UInt32.random(in: 1...5) // 1~5の乱数を取得
dispatchGroup.enter()
dispatchQueue.async {
self.sw[i].start(100 * intResult)
}
Thread.sleep(forTimeInterval: 0.1)
}
}
public func stop() {
for i in 0..<3 {
sw[i].stop()
}
status = false;
dispatchGroup.leave()
print()
}
public func getStatus() -> Bool {
return status
}
}
Main.swift import Foundation
let circuit:Circuit = Circuit()
circuit.start()
while(true) {
sleep(1)
if circuit.getStatus() == false {
break
}
}
circuit.stop()
|
Mediatorパターンを使用した例 Colleague.swift public class Colleague {
internal var mediator:IMediator!
internal func setMediator(_ mediator:IMediator) {
self.mediator = mediator
}
}
Switch.swift import Foundation
public class Switch : Colleague {
private var status:Bool = true // スイッチ(閉)
private var run:Bool = true
private interval:Int = 0;
internal func start(_ n:UInt32) {
let interval:Double = Double(n + 500) / 1000.0
while(run) {
let s:Bool = Int.random(in: 0..<10) > 5
if status != s { // 状態が変わったら
status = s
mediator.colleagueChanged() // 通知
}
Thread.sleep(forTimeInterval: interval)
}
}
internal func stop() {
run = false
}
internal func getStatus() -> Bool {
return status
}
}
Circuit.swift import Foundation
public class Circuit : IMediator {
internal var sw:[Switch]
private var n:Int = 0
private var status:Bool = true
private var dispatchGroup:DispatchGroup!
private var dispatchQueue:DispatchQueue!
public init() {
sw = [Switch(), Switch(), Switch()]
for i in 0..<3 {
{
sw[i].setMediator(self)
}
}
public func colleagueChanged() {
if sw[2].getStatus() == true {
lightOn() // 点灯
}
else if sw[0].getStatus() == false {
lightOff() // 消灯
}
else if sw[1].getStatus() == false {
lightOff() // 消灯
}
else {
lightOn() // 点灯
}
}
internal func lightOn() {
print("○", terminator:"") // 点灯
fflush(stdout)
}
internal func lightOff() {
print("●", terminator:"") // 消灯
fflush(stdout)
n += 1
if n >= 5 // 5回消えたら終わり
stop()
}
public func start() {
dispatchGroup = DispatchGroup()
dispatchQueue = DispatchQueue(label: "queue", attributes: .concurrent)
for i in 0..<3 {
let intResult:UInt32 = UInt32.random(in: 1...5) // 1~5の乱数を取得
dispatchGroup.enter()
dispatchQueue.async {
sw[i].start(100 * intResult))
}
Thread.sleep(forTimeInterval: 0.1)
}
}
public func stop() {
for i in 0..<3 {
sw[i].stop()
}
status = false
dispatchGroup.leave()
print()
}
public func getStatus() -> Bool {
return status
}
}
Main.swift import Foundation
let circuit = Circuit();
circuit.start()
while(true) {
sleep(1)
if (circuit.getStatus() == false) {
break
}
}
circuit.stop()
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.kt internal class Switch : Thread() {
private lateinit var circuit: Circuit
private var status: Boolean = true // スイッチ(閉)
private var run: Boolean = true
private var interval: Int = 0
private fun actionPerformed() {
val d: Double = Math.random()
val s: Boolean = d > 0.5
if (status != s) {
status = s
if (circuit.sw[2].getStatus() == true) circuit.lightOn() // 点灯
else if (circuit.sw[0].getStatus() == false) circuit.lightOff() // 消灯
else if (circuit.sw[1].getStatus() == false) circuit.lightOff() // 消灯
else circuit.lightOn() // 点灯
}
}
internal fun start(n: Int) {
interval = n + 500
start()
}
override fun run() {
while (run) {
actionPerformed()
sleep(interval.toLong())
}
}
internal fun stopx() {
run = false
}
private fun getStatus(): Boolean {
return status
}
internal fun setCircuit(circuit: Circuit) {
this.circuit = circuit
}
}
Circuit.kt import java.util.Random
class Circuit {
internal var sw: Array<Switch> = arrayOf(Switch(), Switch(), Switch())
private var n: Int = 0
private var status: Boolean = true
init() {
for (i in 0..2)
{
sw[i].setCircuit(this)
}
}
internal fun lightOn() {
print("○") // 点灯
}
internal fun lightOff() {
print("●") // 消灯
if (++this.n >= 5) // 5回消えたら終わり
stop()
}
fun start() {
val rnd = Random()
for (i in 0..2)
{
val intResult: Int = rand.nextInt(5) + 1 // 1~5の乱数を取得
sw[i].start(100 * intResult)
}
}
fun stop() {
for (i in 0..2)
{
sw[i].stopx()
}
status = false
}
fun getStatus(): Boolean {
return status
}
}
Main.kt fun main() {
val circuit = Circuit()
circuit.start()
while(true) {
Thread.sleep(1000)
if (!circuit.getStatus()) break
}
circuit.stop()
}
|
Mediatorパターンを使用した例 Colleague.kt open class Colleague : Thread {
internal lateinit var mediator: IMediator
fun setMediator(mediator: IMediator) {
this.mediator = mediator
}
}
Switch.kt class Switch : Colleague() {
internal var status: Boolean = true // スイッチ(閉)
private var run: Boolean = true
private var interval: Int = 0
public fun actionPerformed() {
val d: Double = Math.random()
val s: Boolean = d > 0.5
if (status != s) { // 状態が変わったら
status = s
mediator.colleagueChanged() // 通知
}
}
fun start(n: Int) {
interval = n + 500
start()
}
override fun run() {
while (run) {
actionPerformed()
sleep(interval.toLong())
}
}
public stopx() {
run = false
}
}
IMediator.kt interface IMediator {
fun colleagueChanged()
}
Circuit.kt import java.util.*
class Circuit : IMediator {
private var sw: Array<Switch> = arrayOf(Switch(), Switch(), Switch())
private var n: Int = 0
private var status: Boolean = true
init() {
for (i in 0..2) {
sw[i].setMediator(this)
}
}
override fun colleagueChanged() {
if (sw[2].getStatus() == true) lightOn() // 点灯
else if (sw[0].getStatus() == false) lightOff() // 消灯
else if (sw[1].getStatus() == false) lightOff() // 消灯
else lightOn() // 点灯
}
private fun lightOn() {
print("○") // 点灯
}
private fun lightOff() {
print("●") // 消灯
if (++n >= 5) // 5回消えたら終わり
stop()
}
fun start() {
val rnd = Random()
for (i in 0..2) {
sw[i].start(100 * (rnd.nextInt(5) + 1))
}
}
fun stop() {
for (i in 0..2) {
sw[i].stopx()
}
status = false
}
fun getStatus() : Boolean {
return status
}
}
Main.kt fun main() {
var circuit = Circuit()
circuit.start()
while(true) {
Thread.sleep(1000)
if (!circuit.getStatus()) break
}
circuit.stop()
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.scala class Switch extends Thread() {
private var circuit: Circuit = null
private var status: Boolean = true // スイッチ(閉)
private var running: Boolean = true
private var interval: Int = 0
private def actionPerformed() {
val d: Double = Math.random()
val s: Boolean = d > 0.5
if (status != s) {
status = s
if (circuit.sw(2).getStatus() == true) circuit.lightOn() // 点灯
else if (circuit.sw(0).getStatus() == false) circuit.lightOff() // 消灯
else if (circuit.sw(1).getStatus() == false) circuit.lightOff() // 消灯
else circuit.lightOn() // 点灯
}
}
def start(n: Int) {
interval = n + 500
start()
}
override def run() {
while (running) {
actionPerformed()
Thread.sleep(interval)
}
}
def stop_() {
running = false
}
private def getStatus(): Boolean = status
def setCircuit(circuit: Circuit) {
this.circuit = circuit
}
}
Circuit.scala import scala.util.Random
class Circuit {
var sw = new Array[Switch](3)
for (i <- 0 until 3) {
sw(i) = new Switch()
sw(i).setCircuit(this)
}
private var n: Int = 0
private var status: Boolean = true
def lightOn() {
System.out.print("○") // 点灯
}
def lightOff() {
System.out.print("●") // 消灯
n += 1
if (n >= 5) // 5回消えたら終わり
stop()
}
def start() {
val rnd = new Random()
for (i <- 0 until 3) {
val intResult: Int = rand.nextInt(5) + 1 // 1~5の乱数を取得
sw(i).start(100 * intResult)
}
}
def stop() {
for (i <- 0 until 3) {
sw(i).stop_()
}
status = false
}
def getStatus(): Boolean = status
}
Main.scala import scala.util.control.Breaks
object Main {
def main(args: Array[String]) {
val circuit = new Circuit()
circuit.start()
val b = new Breaks
b.breakable {
while(true) {
Thread.sleep(1000)
if (circuit.getStatus() == false) b.break
}
}
circuit.stop()
}
}
|
Mediatorパターンを使用した例 Colleague.scala class Colleague extends Thread {
protected var mediator: IMediator = null
def setMediator(mediator: IMediator) {
this.mediator = mediator
}
}
Switch.scala class Switch extends Colleague {
private var status: Boolean = true // スイッチ(閉)
private var running: Boolean = true
private var interval: Int = 0
private def actionPerformed() {
val d: Double = Math.random()
val s: Boolean = d > 0.5
if (status != s) { // 状態が変わったら
status = s
mediator.colleagueChanged() // 通知
}
}
def start(n: Int) {
interval = n + 500
start()
}
override def run() {
while (running) {
actionPerformed()
Thread.sleep(interval)
}
}
def stop_() {
running = false
}
def getStatus(): Boolean = status
}
IMediator.scala trait IMediator {
def colleagueChanged(): Unit
}
Circuit.scala import scala.util.Random
class Circuit extends IMediator {
var sw = new Array[Switch](3)
for (i <- 0 until 3) {
sw(i) = new Switch()
sw(i).setCircuit(this)
}
private var n: Int = 0
private var status: Boolean = true
override def colleagueChanged() {
if (sw(2).getStatus() == true) lightOn() // 点灯
else if (sw(0).getStatus() == false) lightOff() // 消灯
else if (sw(1).getStatus() == false) lightOff() // 消灯
else lightOn() // 点灯
}
private def lightOn() {
System.out.print("○") // 点灯
}
private def lightOff() {
System.out.print("●") // 消灯
n += 1
if (n >= 5) // 5回消えたら終わり
stop()
}
fun start() {
val rnd = Random()
for (i <- 0 until 3) {
sw[i].start(100 * (rnd.nextInt(5) + 1))
}
}
fun stop() {
for (i <- 0 until 3) {
sw(i).stop_()
}
status = false
}
fun getStatus() : Boolean = status
}
Main.scala import scala.util.control.Breaks
object Main {
def main(args: Array[String]) {
val circuit = new Circuit()
circuit.start()
val b = new Breaks
b.breakable {
while(true) {
Thread.sleep(1000)
if (circuit.getStatus() == false) b.break
}
}
circuit.stop()
}
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.groovy class Switch extends Thread {
private Circuit circuit
private boolean status = true // スイッチ(閉)
private boolean run = true
private int interval = 0
private void actionPerformed() {
double d = Math.random()
boolean s = d > 0.5
if (status != s) {
status = s
if (circuit.sw[2].status == true)
circuit.lightOn() // 点灯
else if (circuit.sw[0].status == false)
circuit.lightOff() // 消灯
else if (circuit.sw[1].status == false)
circuit.lightOff() // 消灯
else
circuit.lightOn() // 点灯
}
}
protected void start(int n) {
interval = n + 500
start()
}
public void run() {
while(run) {
actionPerformed()
try {
Thread.sleep(interval)
}
catch(Exception x) {}
}
}
protected void stop_() {
run = false
}
}
Circuit.groovy class Circuit {
Switch[] sw
private int n = 0
private boolean status = true
Circuit() {
sw = new Switch[3]
for (int i in 0..<3) {
sw[i] = new Switch()
sw[i].circuit = this
}
}
void lightOn() {
System.out.print("○") // 点灯
}
void lightOff() {
System.out.print("●") // 消灯
if (++n >= 5) // 5回消えたら終わり
stop()
}
void start() {
Random rnd = new Random()
for (int i in 0..<3) {
int intResult = rnd.nextInt(5) + 1 // 1~5の乱数を取得
sw[i].start(100 * intResult)
}
}
void stop() {
for (int i in 0..<3) {
sw[i].stop_()
}
status = false
}
}
Main.groovy class Main {
static void main(String[] args) throws Exception {
Circuit circuit = new Circuit()
circuit.start()
while(true) {
Thread.sleep(1000)
if (circuit.getStatus() == false) break
}
circuit.stop()
}
}
|
Mediatorパターンを使用した例 Colleague.groovy class Colleague extends Thread {
IMediator mediator
}
Switch.groovy public class Switch extends Colleague {
private boolean status = true // スイッチ(閉)
private boolean run = true
private int interval = 0
private void actionPerformed() {
double d = Math.random()
boolean s = d > 0.5
if (status != s) { // 状態が変わったら
status = s
mediator.colleagueChanged() // 通知
}
}
void start(int n) {
interval = n + 500
start()
}
void run() {
while(run) {
actionPerformed()
try {
Thread.sleep(interval)
}
catch(Exception x) {}
}
}
void stop_() {
run = false
}
}
IMediator.groovy interface IMediator {
void colleagueChanged()
}
Circuit.groovy class Circuit implements IMediator {
Switch[] sw
private int n = 0
private boolean status = true
Circuit() {
sw = new Switch[3]
for (int i in 0..<3) {
sw[i] = new Switch()
sw[i].mediator = this
}
}
void colleagueChanged() {
if (sw[2].status == true)
lightOn() // 点灯
else if (sw[0].status == false)
lightOff() // 消灯
else if (sw[1].status == false)
lightOff() // 消灯
else
lightOn() // 点灯
}
private void lightOn() {
System.out.print("○") // 点灯
}
private void lightOff() {
System.out.print("●") // 消灯
if (++n >= 5) // 5回消えたら終わり
stop()
}
void start() {
Random rnd = new Random()
for (int i in 0..<3) {
sw[i].start(100 * (rnd.nextInt(5) + 1))
}
}
public void stop() {
for (int i in 0..<3) {
sw[i].stop_()
}
status = false
}
}
Main.groovy class Main {
static void main(String[] args) throws Exception {
Circuit circuit = new Circuit()
circuit.start()
while(true) {
Thread.sleep(1000)
if (circuit.status == false) break
}
circuit.stop()
}
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.go import (
"math/rand"
"time"
)
type Switch struct {
circuit *Circuit
status bool
running bool
}
func (self *Switch) actionPerformed() {
rand.Seed(time.Now().UnixNano())
var d = rand.Intn(10)
var s = d >= 5
if self.status != s {
self.status = s
if self.circuit.sw[2].status == true {
self.circuit.lightOn() // 点灯
} else if self.circuit.sw[0].status == false {
self.circuit.lightOff() // 消灯
} else if circuit.sw[1].status == false {
self.circuit.lightOff() // 消灯
} else {
self.circuit.lightOn() // 点灯
}
}
func (self *Switch) start(n int) {
var interval = float32(n + 500.0)
for self.running {
self.actionPerformed()
time.Sleep(time.Millisecond * time.Duration(interval)) // 500ミリ秒
}
}
func (self *Switch) stop() {
run = false
}
func NewSwitch() *Switch {
return &Switch {
status: true,
running: true,
}
}
Circuit.go import (
"fmt"
"math/rand"
"time"
)
type Circuit struct {
sw []*Switch
n int
Status boolean
}
func (self *Circuit) lightOn() {
fmt.Print("○") // 点灯
}
func (self *Circuit) lightOff() {
fmt.Print("●") // 消灯
if ++n >= 5 { // 5回消えたら終わり
stop()
}
}
func (self *Circuit) Start() {
rand.Seed(time.Now().UnixNano())
for i:=0; i<3; i++ {
var intResult = rand.Intn(5) + 1 // 1~5の乱数を取得
self.sw[i].circuit = self
go self.sw[i].start(100 * intResult)
}
}
func (self *Circuit) Stop() {
for i:=0; ..<3; i++ {
self.sw[i].stop()
}
self.Status = false
}
func NewCircuit() *Circuit {
return &Circuit {
sw = []*Switch {NewSwitch(),NewSwitch(),NewSwitch(),},
n: 0,
Status: true,
}
}
Main.go import "time"
func main() {
var circuit = NewCircuit()
circuit.Start()
for true {
time.Sleep(time.Second * 1) // 1秒
if circuit.Status == false {
break
}
}
circuit.Stop()
}
|
Mediatorパターンを使用した例 Colleague.go type Colleague struct {
mediator IMediator
}
func (self *Colleague) SetMediator(mediator IMediator) {
self.mediator = mediator
}
Switch.go import (
"math/rand"
"time"
)
type Switch struct {
*Colleague
Status bool // スイッチ(閉)
running bool
}
func (self *Switch) actionPerformed() {
rand.Seed(time.Now().UnixNano())
var d = rand.Intn(10)
var s = d > 0.5
if self.Status != s { // 状態が変わったら
self.Status = s
self.mediator.colleagueChanged() // 通知
}
}
func (self *Switch) start(n int) {
var interval = float32(n + 500)
for self.running {
self.actionPerformed()
time.Sleep(time.Millisecond * time.Duration(interval)) // 500ミリ秒~
}
}
func (self *Switch) stop() {
self.running = false
}
func NewSwitch() *Switch {
return &Switch {
Status: true,
running: true,
Colleague: &Colleague{},
}
}
IMediator.go type IMediator interface {
colleagueChanged()
}
Circuit.go import (
"fmt"
"math/rand"
"time"
)
type Circuit struct {
IMediator {
sw []*Switch
n int
status bool
func (self *Circuit) colleagueChanged() {
if sw[2].Status == true {
self.lightOn() // 点灯
} else if sw[0].Status == false {
self.lightOff() // 消灯
} else if sw[1].Status == false {
self.lightOff() // 消灯
} else {
self.lightOn() // 点灯
}
}
func (self *Circuit) lightOn() {
fmt.Print("○") // 点灯
}
func (self *Circuit) lightOff() {
fmt.Print("●") // 消灯
self.n += 1
if n >= 5 { // 5回消えたら終わり
self.stop()
}
}
func (self *Circuit) start() {
rand.Seed(time.Now().UnixNano())
for i:=0; i<3; i++ {
var intResult = rand.Intn(5) + 1 // 1~5の乱数を取得
self.sw[i].SetMediator(self)
go self.sw[i].start(100 * intResult)
}
}
func (self *Circuit) stop() {
for i=0; i<3; i++ {
self.sw[i].stop()
}
self.Status = false
}
func NewCircuit() *Circuit {
return &Circuit {
sw = []*Switch {NewSwitch(),NewSwitch(),NewSwitch(),},
n: 0,
Status: true,
}
}
Main.go import "time"
func main() {
var circuit = NewCircuit()
circuit.Start()
for true {
time.Sleep(time.Second * 1) // 1秒
if circuit.Status == false {
break
}
}
circuit.Stop()
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 switchx.d import core.thread;
import std.random;
import circuit;
public class Switch : Thread {
private Circuit circuit;
private boolean status = true; // スイッチ(閉)
private boolean running = true;
private int interval = 0;
public this() {
super(&run);
}
private void actionPerformed() {
Random rnd = Random(unpredictableSeed);
double d = uniform(0, 10, rnd);
boolean s = d >= 5;
if (status != s) {
status = s;
if (circuit.sw[2].getStatus() == true)
circuit.lightOn(); // 点灯
else if (circuit.sw[0].getStatus() == false)
circuit.lightOff(); // 消灯
else if (circuit.sw[1].getStatus() == false)
circuit.lightOff(); // 消灯
else
circuit.lightOn(); // 点灯
}
}
protected void start(in int n) {
interval = n + 500;
start();
}
public void run() {
while(running) {
actionPerformed();
Thread.sleep(dur!("msecs")(interval)); // ミリ秒
}
}
protected void stop() {
running = false;
}
private boolean getStatus() {
return status;
}
protected void setCircuit(Circuit circuit) {
this.circuit = circuit;
}
}
circuit.d import std.stdio;
import std.random;
import switchx;
public class Circuit {
protected Switch[] sw;
private int n = 0;
private bool status = true;
public this() {
sw = new Switch[3];
foreach (int i; 0..3) {
sw[i] = new Switch();
sw[i].setCircuit(this);
}
}
protected void lightOn() {
printf("○"); // 点灯
}
protected void lightOff() {
printf("●"); // 消灯
if (++n >= 5) // 5回消えたら終わり
stop();
}
public void start() {
Random rnd = Random(unpredictableSeed);
foreach (int i; 0..3) {
int intResult = uniform(0, 5, rnd) + 1; // 1~5の乱数を取得
sw[i].start(100 * intResult);
}
}
public void stop() {
foreach (int i; 0..3) {
sw[i].stop();
}
status = false;
}
public boolean getStatus() { return status; }
private void printf(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))));
}
}
main.d import core.thread;
import switchx;
import circuit;
int main() {
Circuit circuit = new Circuit();
circuit.start();
while(true) {
Thread.sleep( dur!("seconds")( 1 ) );
if (circuit.getStatus() == false) break;
}
circuit.stop();
return 0;
}
|
Mediatorパターンを使用した例 colleague.d import std.random;
import imediator;
import switchx;
public class Colleague : Thread {
protected IMediator mediator;
public this(void delegate() dg) {
super(dg);
}
public void setMediator(IMediator mediator) {
this.mediator = mediator;
}
}
switchx.d import core.thread;
import std.random;
import colleague;
public class Switch : Colleague {
private bool status = true; // スイッチ(閉)
private bool running = true;
private int interval = 0;
private void actionPerformed() {
Random rnd = Random(unpredictableSeed);
double d = uniform(0, 10, rnd);
bool s = d >= 5;
if (status != s) { // 状態が変わったら
status = s;
mediator.colleagueChanged(); // 通知
}
}
protected void start(in int n) {
interval = n + 500;
super.start();
}
public void run() {
while(running) {
actionPerformed();
Thread.sleep(dur!("msecs")(interval)); // ミリ秒
}
}
protected void stop() {
running = false;
}
protected boolean getStatus() {
return status;
}
}
imediator.d public interface IMediator {
void colleagueChanged();
}
circuit.d import std.random;
import imediator;
import switchx;
public class Circuit : IMediator {
public Switch[] sw;
private int n = 0;
private bool status = true;
public this() {
sw = new Switch[3];
foreach (int i; 0..3) {
sw[i] = new Switch();
sw[i].setMediator(this);
}
}
public void colleagueChanged() {
if (sw[2].getStatus() == true)
lightOn(); // 点灯
else if (sw[0].getStatus() == false)
lightOff(); // 消灯
else if (sw[1].getStatus() == false)
lightOff(); // 消灯
else
lightOn(); // 点灯
}
private void lightOn() {
printf("○"); // 点灯
}
private void lightOff() {
printf("●"); // 消灯
if (++n >= 5) // 5回消えたら終わり
stop();
}
public void start() {
Random rnd = Random(unpredictableSeed);
for (int i = 0; i < 3; i++)
{
sw[i].start(100 * (uniform(0, 5, rnd) + 1));
}
}
public void stop() {
foreach (int i; 0..3) {
sw[i].stop();
}
status = false;
}
public boolean getStatus() { return status; }
private void printf(T...)(T args) { // Shift JIS 出力
import std, std.windows.charset, core.vararg;
std.stdio.write(to!(string)(toMBSz(std.format.format(args))));
}
}
main.d import core.thread;
import circuit;
int main() {
Circuit circuit = new Circuit();
circuit.start();
while(true) {
Thread.sleep( dur!("seconds")( 1 ));
if (circuit.getStatus() == false) break;
}
circuit.stop();
return 0;
}
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
|
Mediatorパターンを使用しない例 Switch.pas unit UnitSwitch;
interface
uses
System.Classes;
type
Switch = class(TThread)
private
var status:boolean;
var run:boolean;
var interval:integer;
procedure actionPerformed();
public
constructor Create(interval:integer);
procedure Execute; override;
procedure stop();
function getStatus():boolean;
procedure setCircuit(c:TObject); // 循環参照の回避
end;
implementation
uses
UnitCircuit;
var _circuit:Circuit;
constructor Switch.Create(interval:integer);
begin
self.interval := interval + 500;
inherited Create(False);
run := true;
end;
procedure Switch.actionPerformed();
var s:boolean;
begin
s := Random(10) >= 5;
if status <> s then begin
status := s;
if _circuit.sw[2].status = true then begin
_circuit.lightOn(); // 点灯
end
else if _circuit.sw[0].status = false then begin
_circuit.lightOff(); // 消灯
end
else if _circuit.sw[1].status = false then begin
_circuit.lightOff(); // 消灯
end
else begin
_circuit.lightOn(); // 点灯
end
end;
end;
procedure Switch.Execute;
begin
while run do begin
actionPerformed();
Sleep(interval);
end;
end;
procedure Switch.stop();
begin
run := false;
end;
function Switch.getStatus():boolean;
begin
Result := status;
end;
procedure Switch.setCircuit(c:TObject);
begin
_circuit := (c as Circuit); // 循環参照の回避
end;
end.
Circuit.pas unit UnitCircuit;
interface
uses
System.Classes,
System.SysUtils,
UnitSwitch;
type
Circuit = class
private
var n:integer;
var status:boolean;
class var flag:boolean;
public
var sw:array of Switch;
constructor Create();
destructor Destroy(); override;
procedure lightOn();
procedure lightOff();
procedure start();
procedure stop();
function getStatus():boolean;
end;
implementation
constructor Circuit.Create();
var i:integer;
begin
status := true;
flag := true;
n := 0;
SetLength(sw, 3);
Randomize();
for i := 0 to Length(sw)-1 do begin
sw[i] := Switch.Create(100 * (Random(5) + 1));
sw[i].setCircuit(self);
end;
end;
destructor Circuit.Destroy();
var s:Switch;
begin
for s in sw do
s.Free;
end;
procedure Circuit.lightOn();
begin
Write('○'); // 点灯
end;
procedure Circuit.lightOff();
begin
while flag = false do begin
Sleep(100);
end;
flag := false;
Write('●'); // 消灯
INC(n);
if n >= 5 then // 5回消えたら終わり
stop();
flag := true;
end;
procedure Circuit.start();
var s:Switch;
begin
for s in sw do
s.start();
end;
procedure Circuit.stop();
var s:Switch;
begin
for s in sw do
s.stop();
status := false;
end;
function Circuit.getStatus():boolean;
begin
Result := status;
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitSwitch,
UnitCircuit;
var _circuit:Circuit;
begin
_circuit := Circuit.Create();
while True do begin
Sleep(1000);
if _circuit.getStatus() = false then
break;
end;
_circuit.stop();
end.
|
Mediatorパターンを使用した例 Colleague.pas unit UnitColleague;
interface
uses
System.Classes,
UnitIMediator;
type
Colleague = class(TThread)
protected
var mediator:IMediator;
public
procedure setMediator(mediator:IMediator);
end;
implementation
procedure Colleague.setMediator(mediator:IMediator);
begin
self.mediator := mediator;
end;
end.
Switch.pas unit UnitSwitch;
interface
uses
UnitColleague;
type
Switch = class(Colleague)
private
var status:boolean;
var run:boolean;
var interval:integer;
procedure actionPerformed();
public
constructor Create(interval:integer);
procedure Execute; override;
procedure stop();
function getStatus():boolean;
end;
implementation
constructor Switch.Create(interval:integer);
begin
self.interval := interval + 500;
inherited Create(False);
run := true;
end;
procedure Switch.actionPerformed();
var s:boolean;
begin
s := Random(10) >= 5;
if status <> s then begin
status := s;
mediator.colleagueChanged(); // 通知
end;
end;
procedure Switch.Execute;
begin
while run do begin
actionPerformed();
Sleep(interval);
end;
end;
procedure Switch.stop();
begin
run := false;
end;
function Switch.getStatus():boolean;
begin
Result := status;
end;
end.
IMediator.pas unit UnitIMediator;
interface
type
IMediator = interface
procedure colleagueChanged();
end;
implementation
end.
Circuit.java unit UnitCircuit;
interface
uses
System.Classes,
System.SysUtils,
UnitIMediator,
UnitSwitch;
type
Circuit = class(TInterfacedObject, IMediator)
private
var n:integer;
var status:boolean;
class var flag:boolean;
public
var sw:array of Switch;
constructor Create();
destructor Destroy(); override;
procedure colleagueChanged();
procedure lightOn();
procedure lightOff();
procedure start();
procedure stop();
function getStatus():boolean;
end;
implementation
constructor Circuit.Create();
var i:integer;
begin
status := true;
flag := true;
n := 0;
SetLength(sw, 3);
Randomize();
for i := 0 to Length(sw)-1 do begin
sw[i] := Switch.Create(100 * (Random(5) + 1));
sw[i].setCircuit(self);
end;
end;
destructor Circuit.Destroy();
var s:Switch;
begin
for s in sw do
s.Free;
end;
procedure Circuit.colleagueChanged();
begin
if sw[2].getStatus() = true then begin
lightOn(); // 点灯
end
else if sw[0].getStatus() = false then begin
lightOff(); // 消灯
end
else if sw[1].getStatus() = false then begin
lightOff(); // 消灯
end
else begin
lightOn(); // 点灯
end
end;
procedure Circuit.lightOn();
begin
Write('○'); // 点灯
end;
procedure Circuit.lightOff();
begin
while flag = false do begin
Sleep(100);
end;
flag := false;
Write('●'); // 消灯
INC(n);
if n >= 5 then // 5回消えたら終わり
stop();
flag := true;
end;
procedure Circuit.start();
var s:Switch;
begin
for s in sw do
s.start();
end;
procedure Circuit.stop();
var s:Switch;
begin
for s in sw do
s.stop();
status := false;
end;
function Circuit.getStatus():boolean;
begin
Result := status;
end;
end.
Main.dpr program Main;
uses
System.SysUtils,
UnitColleague,
UnitIMediator,
UnitSwitch,
UnitCircuit;
var _circuit:Circuit;
begin
_circuit := Circuit.Create();
while True do begin
Sleep(1000);
if _circuit.getStatus() = false then
break;
end;
_circuit.stop();
end.
|
|
スイッチは0.1秒ごと状態が変化する可能性があります。そして、その都度、すべてのスイッチが他のスイッチの状況を確認し電球の状況を変更しています。これでは、条件が複雑になるにつれ、どこで何をチェックしているのか管理できなくなってきてしまいます。 この例では、スイッチという一種類だけのオブジェクトでしたが、これが何種類もあって、条件判定がそれぞれ違っていたらどうでしょうか。 そして、1つのオブジェクトの内容を改造したらどうなるでしょうか? 他のすべてのオブジェクトに影響を及ぼしてしまいます。新たなオブジェクト(例えば電池)を追加する場合も、それと関連する複数のオブジェクト(スイッチ)に何らかの改造が必要になるはずです。プログラムを改造したら、テストしなければなりません。たった1つのオブジェクトを改造や追加したことで、プログラムの多くの部分をテストし直さなければならなくなります。 |
Mediatorパターンで記述するとどうでしょう。状態が変わったときだけ呼び出され確認しています。 Mediator パターンでは、各オブジェクトは、自分の状態が変わったときに、Mediator に連絡し、 Mediator は、状態が変わったオブジェクトだけでなく、各オブジェクトの状態を総合的に判断し、 処理を行うわけです。 Circuit のインスタンスが生成されたとき、各スイッチのインスタンスも生成され、それらには、Circuit のインスタンスが設定されます。各スイッチは、状態が変わったら、Circuit のインスタンスの colleagueChanged() メソッドを呼び出します。colleagueChanged() メソッドは、各スイッチの状態を調べ、点灯か消灯かを表示します。 もし、スイッチを改造したり、電池などを追加したとしても、影響を及ぼすのは Mediator である Circuit だけで済みます。Circuit の中で、スイッチの改造を吸収してしまえば、スイッチや電池などの改造は不要になります。 |
オブジェクト指向プログラミングの成功の秘訣として「できるだけオブジェクト間の関連を少なくする」ということがあります。Mediatorパターンを採用することで、オブジェクト間の関連の数を少なくできます。相互に関連を持っていれば、その関連の数は、オブジェクトが4つなら6本ですし、オブジェクトが5つなら10本ですが、Mediatorパターンではオブジェクトが4つなら4本、5つなら5本で済みます。