1
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?

#0094(2025/04/05) オープン・クローズドの原則(Open/Closed Principle: OCP)

Last updated at Posted at 2025-04-05

オープン・クローズドの原則(Open/Closed Principle: OCP)

オープン・クローズドの原則(Open/Closed Principle: OCP)は、ロバート・C・マーチンによって提唱されたSOLID原則の一つで、「ソフトウェアの要素は拡張に対して開いており、変更に対して閉じているべき」という考え方です。この記事では、上級プログラマー向けに、PythonとTypeScriptを用いてOCPが守られている例・守られていない例を具体的に示します。

オープン・クローズドの原則(OCP)の本質

OCPの本質は、既存コードを変更せずに新しい機能を追加できるように設計することです。これにより、変更による影響範囲を抑え、柔軟な拡張性を確保します。


Pythonによる例

❌ OCPが守られていない例

class DiscountCalculator:
    def calculate_discount(self, customer_type, total):
        if customer_type == 'regular':
            return total * 0.1
        elif customer_type == 'premium':
            return total * 0.2
        # 新しい顧客タイプを追加する場合、このクラスを直接修正する必要がある

新しい顧客タイプが追加されるたびに、このクラスを修正する必要があるため、変更に弱い構造となっています。

✅ OCPが守られている例

from abc import ABC, abstractmethod

class DiscountStrategy(ABC):
    @abstractmethod
    def apply_discount(self, total):
        pass

class RegularDiscount(DiscountStrategy):
    def apply_discount(self, total):
        return total * 0.1

class PremiumDiscount(DiscountStrategy):
    def apply_discount(self, total):
        return total * 0.2

class DiscountCalculator:
    def __init__(self, strategy: DiscountStrategy):
        self.strategy = strategy

    def calculate_discount(self, total):
        return self.strategy.apply_discount(total)

新しい顧客タイプが増えた際には新しいクラスを追加するだけで済み、既存コードへの変更が不要です。


TypeScriptによる例

❌ OCPが守られていない例

class PaymentProcessor {
    processPayment(method: string, amount: number) {
        if (method === 'creditCard') {
            console.log(`Processing credit card payment of ${amount}`);
        } else if (method === 'paypal') {
            console.log(`Processing PayPal payment of ${amount}`);
        }
        // 新しい支払い方法を追加する場合、このクラスを直接修正する必要がある
    }
}

支払い方法の追加があった際、このクラスを修正する必要があり、変更の影響を受けやすい設計です。

✅ OCPが守られている例

interface PaymentMethod {
    pay(amount: number): void;
}

class CreditCardPayment implements PaymentMethod {
    pay(amount: number): void {
        console.log(`Processing credit card payment of ${amount}`);
    }
}

class PayPalPayment implements PaymentMethod {
    pay(amount: number): void {
        console.log(`Processing PayPal payment of ${amount}`);
    }
}

class PaymentProcessor {
    constructor(private paymentMethod: PaymentMethod) {}

    process(amount: number): void {
        this.paymentMethod.pay(amount);
    }
}

新しい支払い方法が必要になった場合、新しいクラスを追加するだけで済み、既存の処理に影響を与えません。


オープン・クローズドの原則のopen/closedについて

Openの意味:「拡張に対して開かれている」

  • 新しい機能や振る舞いを追加したい時に、既存のコードを変更せずに新しいコードを追加することで機能拡張できることを指します。

Openであるべき点(拡張可能な部分)

  • 新しいクラスの追加(例:新しい割引方法、新しい決済方法)
  • インターフェースを利用した新しい実装クラスの導入

Closedの意味:「変更に対して閉じている」

  • 一度書いたコードを、既存機能を変更することなく安定的に保ち、修正の影響を最小限に抑えることを指します。

Closedであるべき点(変更されない部分)

  • 既存のクラスや関数の内部実装
  • すでに動作確認済みの重要なロジック

まとめ

オープン・クローズドの原則を守ることで、ソフトウェアは変更に強く、拡張が容易な構造になります。上級プログラマーとしては、この原則を実践しつつも、過度な抽象化を避け、現実的かつ保守性の高いコード設計を意識することが重要です。

1
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
1
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?