Featured image of post コードドクター【Facade】総合受付(General Reception)〜スマートホームの混沌〜

コードドクター【Facade】総合受付(General Reception)〜スマートホームの混沌〜

「先生! 家が……私の家が私を拒絶しているんです!」

診察室の重い鉄扉を引いた瞬間、私は足をもつれさせて床に倒れ込んだ。 体中に巻きついた何本ものケーブルが、まるで鎖のように私を縛り付けている。 私のベストには、テレビ、エアコン、照明、オーディオ……ありとあらゆるリモコンがマジックテープで貼り付けられている。まるで全身がスイッチの塊のようだ。

「患者さん、落ち着いてください」

助手のナナコが駆け寄り、私の足に絡まった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)

治療のステップ

  1. 執事の雇用 — サブシステムをラップするFacadeクラスを作成する。
  2. 窓口の設置 — クライアントが望むシンプルなインターフェース(メソッド)を定義する。
  3. 詳細の隠蔽 — 複雑な初期化や呼び出し順序をFacadeの内部メソッドに移動する。
  4. バイパスの許可 — 上級ユーザーがサブシステムに直接アクセスする道は残しておく。

助手より

スマートホーム、憧れますよね! でも、リモコンが多すぎて映画を見るのに10分もかかっていては本末転倒です。 まずは「よく使うセット」をボタン一つにまとめることから始めてみましょう。Perlのモジュール設計でも、「とりあえずこれを使えばOK」という簡単なインターフェースを用意してあげると、未来の自分やチームメンバーが救われますよ!

——ナナコ

comments powered by Disqus
Hugo で構築されています。
テーマ StackJimmy によって設計されています。