0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

オープンクローズドの原則について理解する

Last updated at Posted at 2025-11-09

まとめ

  • オープンクローズドの原則は「拡張に対して開いている」と「修正に対して閉じている」を同時に満たすこと
  • オープンクローズドの原則に従うと既存のコードに影響を与えずに機能の拡張ができる

背景

社内の勉強会でSOLID原則を扱っていて今回はオープンクローズドの原則について予習します。

オープンクローズドの原則とは

拡張に対して開いている」と「修正に対して閉じている」を同時に満たす設計のことです。

拡張に対して開いているとは「コードの振る舞いを拡張できる」という意味です。

修正に対して閉じているとは「コードの振る舞いを拡張しても、その他のコードはまったく影響を受けない」という意味です。

引用
https://www.shuwasystem.co.jp/book/9784798046143.html

オープンクローズドの原則に従っていない例

Userクラスを例にします。
Userクラスにはインスタンス変数にpermissionを持っていて、これで権限を設定できます。

class User {
    name: string;
    email: string;
    permission: string;
    
    constructor(name: string, email: string, permission: string) {
        this.name = name;
        this.email = email;
        this.permission = permission;
    }

    getPermission(): void {
        switch(this.permission) {
            case 'admin':
                console.log('管理者権限があります');
                break;
            case 'editor':
                console.log('編集者権限があります');
                break;
            case 'viewer':
                console.log('閲覧者権限があります');
                break;
            default:
                console.log('不明な権限です');
        }
    }
}

const user1 = new User('山田太郎', 'yamada@example.com', 'admin');
user1.getPermission(); // 管理者権限があります

const user2 = new User('鈴木花子', 'suzuki@example.com', 'viewer');
user2.getPermission(); // 閲覧者権限があります

このclassを拡張する必要が出てきました。
例えば、新しい権限としてゲスト権限を追加したい場合です。

以下のようにするとコードを拡張できましたが、既存のコードを修正しています。
よってこれはオープンクローズドの原則を違反しています。

 getPermission(): void {
        switch(this.permission) {
            case 'admin':
                console.log('管理者権限があります');
                break;
            case 'editor':
                console.log('編集者権限があります');
                break;
            case 'viewer':
                console.log('閲覧者権限があります');
                break;
            case 'guest':
                console.log('ゲスト権限があります');
                break;
            default:
                console.log('不明な権限です');
        }
    }

オープンクローズドの原則に従っている例

Permissionをinterfaceとして定義し、管理者権限や各権限がそのinterfaceを実装するようにします。

image.png

interface Permission {
  showPermission(): void;
}

class AdminPermission implements Permission {
  showPermission() {
    console.log('管理者権限があります');
  }
}

class EditorPermission implements Permission {
  showPermission() {
    console.log('編集者権限があります');
  }
}

class ViewerPermission implements Permission {
  showPermission() {
    console.log('閲覧者権限があります');
  }
}

class User {
  name: string;
  email: string;
  permission: Permission;

  constructor(name: string, email: string, permission: Permission) {
    this.name = name;
    this.email = email;
    this.permission = permission;
  }

  showPermission() {
    this.permission.showPermission();
  }
}

const user1 = new User("山田太郎", "yamada@example.com", new AdminPermission());
user1.showPermission(); // 管理者権限があります

const user2 = new User('鈴木花子', 'suzuki@example.com', new ViewerPermission());
user2.showPermission(); // 閲覧者権限があります

この設計で新しい権限としてゲスト権限を追加します。
以下を実装するだけで拡張が可能です。これは既存のコードに影響を与えていないのでオープンクローズドの原則に従っていると言えます。

class GuestPermission implements Permission {
  showPermission() {
    console.log('ゲスト権限があります');
  }
}

Goでも書いてみました。

type Permission interface {
	showPermission()
}

type AdminPermission struct{}

func (a AdminPermission) showPermission() {
	println("管理者権限があります")
}

type EditorPermission struct{}

func (e EditorPermission) showPermission() {
	println("編集者権限があります")
}

type ViewerPermission struct{}

func (v ViewerPermission) showPermission() {
	println("閲覧者権限があります")
}

type user struct {
	name       string
	email      string
	permission Permission
}

func (u user) showUserPermission() { u.permission.showPermission() }

func main() {
	editor := user{name: "Alice", email: "alice@example.com", permission: EditorPermission{}}
	editor.showUserPermission()
}

Goのインタフェースは他の言語とは異なり「暗黙的に」実装されます。
具象型の方ではあるインターフェイスを実装するかを宣言しません。
具象型Cのメソッド群がインターフェースIのメソッド群を完全に含めば、具象型CはインターフェイスIを実装することができます。

引用
https://www.oreilly.co.jp/books/9784814401192/

まとめ

  • オープンクローズドの原則は拡張に対して開いている」と「修正に対して閉じている」を同時に満たすこと
  • オープンクローズドの原則に従うと既存のコードに影響を与えずに機能の拡張ができる

今後勉強したいこと

  • 流動的要素のカプセル化
  • OCPを実現する手段としてのStrategyパターン等のデザインパターン
  • バリエーション防護壁

参考

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?