「先生! 家が……私の家が私を拒絶しているんです!」
診察室の重い鉄扉を引いた瞬間、私は足をもつれさせて床に倒れ込んだ。
体中に巻きついた何本ものケーブルが、まるで鎖のように私を縛り付けている。
私のベストには、テレビ、エアコン、照明、オーディオ……ありとあらゆるリモコンがマジックテープで貼り付けられている。まるで全身がスイッチの塊のようだ。
「患者さん、落ち着いてください」
助手のナナコが駆け寄り、私の足に絡まったLANケーブルを解こうとする。
しかし、私は悲鳴を上げた。
「青いケーブルには触らないで! それを抜くと、コーヒーメーカーの抽出温度がリセットされてしまう!」
ドクターはカルテに目を落としたまま、静かに言った。
「……重症(Critical)。『設定疲労(Config Fatigue)』の末期だ」
診察:マイクロマネジメント地獄
私は、震える手でタブレットを差し出した。
そこには、私が自慢の「スマートホーム」を制御するために書いたPerlスクリプト bad_cinema.pl が映し出されていた。
「見てください。私はただ、映画が見たかっただけなんです。でも、『観賞モード』にするには、カーテンを閉めて、スクリーンを下ろして、プロジェクターの入力を切り替えて……その順番を一つでも間違えると、なぜかスプリンクラーが作動して庭が水浸しになるんです!」
ドクターは眼鏡の位置を直し、コードを覗き込んだ。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
| use v5.36;
use Device::Light;
use Device::Curtain;
use Device::Screen;
use Device::Projector;
use Device::Amp;
use Device::Bluray;
use Device::PopcornMaker;
# 1. Lights down (but not too dark, or I trip)
my $light = Device::Light->new(room => 'living');
$light->set_brightness(10);
# 2. Curtain close
my $curtain = Device::Curtain->new();
$curtain->close(speed => 'slow'); # Don't scare the cat
# 3. Screen down
my $screen = Device::Screen->new();
$screen->down();
# 4. Projector on
my $projector = Device::Projector->new();
$projector->on();
$projector->set_input('HDMI1');
# 5. Amp on
my $amp = Device::Amp->new();
$amp->set_volume(11); # Spinal Tap style
$amp->set_source('HDMI');
# 6. Bluray play
my $bluray = Device::Bluray->new();
$bluray->play();
# 7. Popcorn?
my $popcorn = Device::PopcornMaker->new();
$popcorn->pop();
say "Enjoy the movie!";
|
「美しい……」
私はうっとりとした気分で呟いた。
「全てのデバイスを私が直接制御している。この『全能感』こそがスマートホームの醍醐味でしょう?」
「……否(Negative)。全能ではない。ただの『酷使(Abuse)』だ」
「こ、酷使?」
「……過干渉(Interference)。個別の制御は破綻を招く」
ナナコが補足する。
「そうですよ! 映画を見るたびに、照明係さんやカーテン係さん全員にいちいち指示を出しているようなものです。一人でも急にやり方を変えたら、もう映画どころじゃありません。まるでオーケストラの指揮者が、演奏中にバイオリニストの指を押さえにいってるみたいですね」
「……肯定(Affirmative)。必要なのは『執事(Butler)』だ」
治療:Facade(正面玄関)の設置
ドクターはキーボードを叩き始めた。
「……処方(Prescription)。Facadeパターン。複雑なサブシステム(Subsystem)の前に、窓口(Interface)を置く」
「ご主人様の代わりに、ややこしい家電たちをまとめて操作してくれる『執事さん』を雇いましょう、ということですね!」ナナコが頷く。
Step 1: 執事(Facade)の処方
ドクターは Home::TheaterFacade という新しいクラスを作成した。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
| package Home::TheaterFacade;
use v5.36;
use Device::Light;
use Device::Curtain;
use Device::Screen;
use Device::Projector;
use Device::Amp;
use Device::Bluray;
use Device::PopcornMaker;
sub new ($class) {
return bless {}, $class;
}
sub watch_movie ($self, $movie_name) {
say "$movie_name の上映準備を始めます...";
# 環境の調整(照明・スクリーン)
$self->_dim_lights();
$self->_prepare_screen();
# 音響・映像の準備
$self->_setup_av_system();
# スナックの用意
$self->_make_popcorn();
say "上映開始。お楽しみください。";
}
sub end_movie ($self) {
say "シアターモードを終了します...";
# 終了処理も一括で行う
Device::Light->new(room => 'living')->set_brightness(100);
Device::Screen->new()->up();
Device::Projector->new()->off();
Device::Amp->new()->off();
Device::Bluray->new()->stop();
}
# --- Private "Butler" Methods ---
# 複雑な詳細はここに隠蔽する
sub _dim_lights ($self) {
my $light = Device::Light->new(room => 'living');
$light->set_brightness(10);
}
sub _prepare_screen ($self) {
Device::Curtain->new()->close(speed => 'slow');
Device::Screen->new()->down();
}
sub _setup_av_system ($self) {
my $projector = Device::Projector->new();
$projector->on();
$projector->set_input('HDMI1');
my $amp = Device::Amp->new();
$amp->set_volume(20); # 耳に優しい音量に調整
$amp->set_source('HDMI');
Device::Bluray->new()->play();
}
sub _make_popcorn ($self) {
Device::PopcornMaker->new()->pop();
}
1;
|
「……観察せよ(Observe)。細部は、Privateメソッドに隠蔽(Encapsulate)した」
私は不安そうに尋ねる。
「でも先生、それだと私が『今日は音量11で聞きたい』と思った時に困るんじゃ……」
「……直接操作せよ。Facadeは『一般化(Generalization)』だ。詳細へのアクセスは禁止していない」
「執事さんがいても、ご主人様が自分でやりたい時は自分でやっていいんです。こだわりのある部分は自由なんですよ」とナナコが笑顔を見せる。
Step 2: 処方後の生活(Client Code)
ドクターは、私のスクリプト good_cinema.pl を書き換えた。
1
2
3
4
5
6
7
8
9
10
| use v5.36;
use Home::TheaterFacade;
my $theater = Home::TheaterFacade->new();
# ボタン一つで、全てが整う
$theater->watch_movie("The Matrix");
# 終わったら、片付けも一発
# $theater->end_movie();
|
ナナコがモニターを覗き込んで感心する。
「50行あったコードが、たった数行になりました。これなら、猫がキーボードの上を歩いてもスプリンクラーは作動しません」
予後
後日、私は再び診療所を訪れた。
以前のようなケーブルの絡まりはなく、身軽な服装だ。
「先生、おかげさまで快適です。最近は家族も映画を見てくれるようになりました。『パパの作ったシステム、やっと使えるようになったね』って」
「……重畳(Satisfactory)」
私は照れくさそうに笑いながら、ポケットから小さな小さなリモコンを取り出した。
「実はこれ……ポップコーンメーカーの『塩加減』だけを微調整するための専用リモコンなんです。これだけは、どうしても執事には任せられなくて」
ナースのナナコが吹き出した。
「やっぱり! こだわりは捨てられないんですね」
ドクターは無表情にカルテを閉じた。
複雑さを隠すことはできても、マニアの情熱までは隠蔽できないようだ。
私は一礼し、診察室の扉を押して廊下へと出た。
処方箋まとめ
| 症状 | 適用すべき | 経過観察 |
|---|
| 複数のクラスを特定の順序で呼び出す必要がある | ✓ | |
| ライブラリの内部構造が複雑すぎる | ✓ | |
| 単にクラス名を短くしたいだけ(Alias) | | ✓ |
治療のステップ
- 執事の雇用 — サブシステムをラップするFacadeクラスを作成する。
- 窓口の設置 — クライアントが望むシンプルなインターフェース(メソッド)を定義する。
- 詳細の隠蔽 — 複雑な初期化や呼び出し順序をFacadeの内部メソッドに移動する。
- バイパスの許可 — 上級ユーザーがサブシステムに直接アクセスする道は残しておく。
助手より
スマートホーム、憧れますよね! でも、リモコンが多すぎて映画を見るのに10分もかかっていては本末転倒です。
まずは「よく使うセット」をボタン一つにまとめることから始めてみましょう。Perlのモジュール設計でも、「とりあえずこれを使えばOK」という簡単なインターフェースを用意してあげると、未来の自分やチームメンバーが救われますよ!
——ナナコ