冷房/暖房を考慮したエアコン制御ロジックの再設計
はじめに
前回までで、以下の機能は一通り実装できていた。
一通り動くようになったあと、 制御ロジックをあらためて眺めてみたところ、気になる点が出てきた。
エアコンの運転モード(冷房/暖房)をまったく意識していなかった
という点である。
既存制御ロジックの内容
修正前のエアコン制御ロジックは、次のような条件分岐だった。
if (currentTemperature >= temperatureThresholdHigh && !airConditionerState) { controlAirConditioner(true); airConditionerState = true; } else if (currentTemperature <= temperatureThresholdLow && airConditionerState) { controlAirConditioner(false); airConditionerState = false; }
このロジックは、
- 温度が高くなったらエアコンを ON
- 温度が下がったらエアコンを OFF
という動きをしている。
当初は「とりあえず動けばOK」と思っていたので、 この時点では特に違和感はなかった。
暗黙的前提条件の存在
ただ、よく考えてみると、 このロジックが自然に成立するのは 冷房の場合だけである。
つまり、
- 暖房運転をしたい場合
- 冷房と暖房を切り替えて使いたい場合
には、このままでは対応できない。
ロジックの中に、
「今は冷房なのか、暖房なのか」
という情報が存在していなかった。
問題構造の整理
ここで一度、前提を整理してみる。
エアコンの実際の仕様
- 冷房と暖房がある
- 冷房と暖房では、温度制御の考え方が逆になる
今のロジックで足りていない点
- 冷房/暖房という状態を保持していない
- 温度判定のルールが 1 パターンしかない
結果として、
冷房で使うことを前提にしたロジックになっていた
という状態だった。
要件の再整理
コードから一度離れて、 「やりたいこと」を書き出してみる。
やりたかったこと
- 冷房と暖房を切り替えられるようにしたい
- モードに応じて ON / OFF の判断を変えたい
温度判定の整理
| 運転モード | ON 判定 | OFF 判定 |
|---|---|---|
| 冷房 | 高温閾値を上回ったとき | 低温閾値を下回ったとき |
| 暖房 | 低温閾値を下回ったとき | 高温閾値を上回ったとき |
同じ「高/低閾値」でも、 意味が逆になることが分かる。
運転モード表現の必要性
ここまで整理してみて、 そもそも「今が冷房か暖房か」を プログラムが知らないと判断できない、ということに気づいた。
そこで、運転モードをどう表現するかを考えた。
真偽値による運転モード表現
bool isCooling;
考え方
trueなら冷房falseなら暖房
という 2 択で表す方法である。
書き方の例
if (isCooling) { // 冷房時の制御 } else { // 暖房時の制御 }
使ってみて感じたこと
シンプルではあるが、
true/falseの意味を毎回思い出す必要がある- あとからモードを増やしたくなったときに困りそう
という点が少し気になった。
列挙型による運転モード表現
enum class AcMode { Cooling, Heating };
相違点
AcMode という型自体が、
「エアコンの運転モード」を表すようになる。
AcMode::CoolingAcMode::Heating
と書けるので、意味がコード上にそのまま出てくる。
条件分岐の例
if (acMode == AcMode::Cooling) { // 冷房用制御 }
読み返したときに、 「何を判定しているのか」を考えなくて済む。
安全性について
enum class は、
意図しない値を代入できない。
acMode = 1; // コンパイルエラー acMode = true; // コンパイルエラー
うっかりしたミスを 早い段階で防げるのは助かる。
拡張を考えた場合
将来、
- 送風
- 除湿
を足したくなった場合も、 自然に拡張できそうだと感じた。
enum class AcMode { Cooling, Heating, Fan, Dry };
本システムでの選択
今回のシステムでは、
- 実際の機器を動かす
- 間違った制御は困る
- あとから機能を足す可能性が高い
という前提がある。
そのため、
現時点では
enum classを使用する
とした。
修正後制御ロジックの構造
運転モードごとに、 判定ロジックを分ける形にした。
冷房モード時
if (currentTemperature >= temperatureThresholdHigh && !airConditionerState) { controlAirConditioner(true); airConditionerState = true; } else if (currentTemperature <= temperatureThresholdLow && airConditionerState) { controlAirConditioner(false); airConditionerState = false; }
暖房モード時
if (currentTemperature <= temperatureThresholdLow && !airConditionerState) { controlAirConditioner(true); airConditionerState = true; } else if (currentTemperature >= temperatureThresholdHigh && airConditionerState) { controlAirConditioner(false); airConditionerState = false; }
条件式は似ているが、 考え方はまったく逆になっている。