カウンタクラス(機能合成)

生田 陸人
LuaGate エンジニア / 現役エンジニア
編集 LuaGate編集部

カウンタクラス(機能合成)

このレッスンで分かること

  • オブジェクトの本質は「データ (状態) と 振る舞い (操作) を一体化させる」点にある
  • OOP の最大の特徴は、クラス状態 (state) を持てる ことです
  • Counter クラスには次の機能を持たせます

カウンタクラス とは

状態を持つカウンタを クラス で実装し、counterOps(ops)inc / dec / reset の操作を順に適用して最終値を返す。

OOP の最大の特徴は、クラス状態 (state) を持てる ことです。関数 だけで書くと、状態を 引数戻り値 で持ち回さなければなりませんが、クラスインスタンス は内部の 属性状態 を保持できます。本レッスンでは、最もシンプルな状態保持の例として カウンタ を実装します。

オブジェクトの本質は「データ (状態) と 振る舞い (操作) を一体化させる」点にある。

Counter クラスの設計

Counter クラスには次の機能を持たせます。

  • 属性value (現在のカウント値、初期 0)
  • inc()value を 1 増やす
  • dec()value を 1 減らす
  • reset()value を 0 に戻す
  • current() — 現在の value を返す

Python

class Counter: def __init__(self): self.value = 0 def inc(self): self.value += 1 def dec(self): self.value -= 1 def reset(self): self.value = 0 def current(self): return self.value

5 つのメソッドを 1 つの クラス にまとめることで、「カウンタ として振る舞うオブジェクト」を作れます。Counter() でインスタンスを作るたびに、独立した 状態 を持つカウンタが生まれます。

インスタンスは独立

Python

c1 = Counter() c2 = Counter() c1.inc() c1.inc() c2.inc() print(c1.current()) # 2 print(c2.current()) # 1

c1c2 はそれぞれ別のオブジェクトで、value 属性も別々に持ちます。これが グローバル変数 と違うところで、複数の カウンタ を同時に動かせます。

操作列を適用する流れ

操作列を順に適用するパターンを図にすると次のとおりです。

diagram (will load when visible)

図のポイント (テキスト併記)

  • 各操作は インスタンスvalue を更新する 副作用 を持ちます

各操作は インスタンスvalue を更新する 副作用 を持ちます。関数型 プログラミングでは 副作用 を避ける傾向がありますが、OOP では「オブジェクトの状態を変える のは、そのオブジェクトのメソッドだけ」というルールで 副作用 をコントロールします。これを カプセル化 と呼びます。

JavaScript での実装

JavaScript

class Counter { constructor() { this.value = 0; } inc() { this.value += 1; } dec() { this.value -= 1; } reset() { this.value = 0; } current() { return this.value; } }

Java でも同じ構造で書けますが、本問では PythonJavaScript のみ対応します。

このレッスンでやること

関数 counterOps(ops) を実装してください。ops は文字列の配列で、各要素は "inc" / "dec" / "reset" のいずれか。Counter クラスを内部で作り、ops を順に適用した後、最終的な value整数 で返します。例として ["inc", "inc", "dec", "inc"]2["inc", "inc", "reset"]0

よくある間違い

  • self.value = 0Counter.value = 0 と書いてしまう (クラス変数 になり、全インスタンスで共有される)。
  • inc の中で value += 1 (self なし) と書いて、ローカル変数を 1 にして終わる。self.value += 1 が正解。
  • 戻り値を 配列 にしてしまう。本問では 最終値の整数 だけを返す。

カプセル化のメリット

カプセル化 は、状態 を外から直接いじれないようにし、メソッド 経由でしか変更できなくする原則だ。

Counter クラスを使う側は、内部の value 属性を直接書き換えるのではなく、inc()reset() を呼びます。これによって、カウンタ の振る舞いが「プラス 1」「マイナス 1」「ゼロに戻す」の 3 種類だけに限定され、予期しない値の代入を防げます。Java などの言語では private キーワードで属性へのアクセスを文法的に制限できます。Python は文法的な強制はありませんが、慣例として _value (アンダースコア始まり) を「外から触らないでね」のサインに使います。

状態を直接いじれる場所が増えるほど、バグ の原因も増える。カプセル化 は「バグ の出口を狭める」設計原則だ。

やってみよう

OOP の「状態 + 操作」のセットを、Counter という最小例で体感してください。スタック キュー も、突き詰めれば「状態 = items 配列操作 = push/pop など」という同じパターンの応用です。

よくある質問

Q. このトピックは実務でどう役立ちますか?

A. DB のクエリ最適化、API 設計、データ構造の選択など、設計判断の根拠になります。表面的にライブラリを使うだけでなく「なぜそれが速いのか」を理解できると、性能問題を未然に防げます。コーディング面接でも頻出のテーマです。

Q. 計算量はどう求めれば良いですか?

A. ループのネストごとに掛け算する、再帰なら漸化式から解く、というのが基本です。Big-O 表記は定数倍と低次の項を無視するため、n の指数(n²、n log n など)に注目してください。最悪・平均・最良の 3 つを意識すると説得力が増します。

Q. 覚えるべき定番アルゴリズムは何ですか?

A. 二分探索、クイックソート/マージソート、BFS/DFS、ダイクストラ、DP の基本問題(フィボナッチ・ナップサック)が必修です。これらを「白紙から書ける」状態にすると、応用問題が一気に解けるようになります。

次のレッスン

次は 第 5 章クイズ — クラスと OOP で、第 5 章クイズ — クラスと OOP を学びます。

事前確認 — 進む前に次の 3 つができることを確認しましょう。

  1. カウンタクラス の要点を自分の言葉で説明できる
  2. このレッスンの最小コード (または操作手順) を見ずに書ける
  3. 練習問題やクイズで間違えた箇所を読み直して理解した

理解度チェック (30 秒)

Q. カウンタクラス とは何か、1 文で説明してください。

この章のポイント

A. 本文の「このレッスンで分かること」または冒頭の説明文を見直し、自分の言葉で要約できれば OK。詰まったら本レッスンの最初の H2 セクションを読み返してみましょう。

関連レッスン

要件

  1. 関数 counterOps(ops) を実装し、最終的なカウンタ値を整数で返す
  2. 内部に Counter クラスを定義し、value 属性と inc / dec / reset メソッドを持たせる
  3. ops を 1 つずつ取り出し、対応するメソッドを呼ぶ

入出力例

test-cases.txt

counterOps(["inc","inc","dec","inc"])2 counterOps(["inc","inc","reset","inc"])1 counterOps(["inc","inc","inc","reset"])0 counterOps(["dec","dec","dec"])-3 counterOps([])0 counterOps(["inc","inc","inc","inc","inc"])5

ヒント

main.py
main.py
学習モード

メモ

カウンタクラス(機能合成)

⌘S で保存