コードで見るSOLID原則:オープン・クローズドの原則

目次:

オープン・クローズドの原則(OCP)ってドユコト?

説明しよう。OCP(Open-Closed Principle)とは。

ソフトウェアの設計原則の一つで、ソフトウェアの実体(クラス、モジュール、関数など)は、”拡張に対してはオープンであるが、変更に対してはクローズであるべきである”とするものである。つまり、既存のコンポーネントは、新しい要件に対応するために、既存のコードに変更を加えることなく拡張できるように記述する必要がある。

ソフトウェアの複雑性によく効くの?

OCPは、開発者に柔軟で再利用可能なコンポーネントを書くように促すので、ソフトウェアの複雑さを軽減することができます。OCPに従うことで、開発者は、基盤となるコードを変更することなく、既存のコンポーネントを拡張して新しい要件に対応することができます。これにより、新たなバグを発生させたり、既存の機能を破壊したりするリスクを低減することができます。

テストのし易さによく効くの?

OCPでは、コンポーネントを分離してテストすることが容易になるため、テストのしやすさが向上します。テストは、コンポーネントの実装ではなく、コンポーネントの動作に焦点を当てて書くことができ、テストを理解し、保守することが容易になります。さらに、あるコンポーネントを変更しても、システムの他の部分に影響を与える可能性が低く、 既存のテストが壊れるリスクも低くなります。

ソフトウェアを変更しやすくなるの?

OCPでは、新しい要件に対応するためにシステムを変更することが容易になるため、変更の容易性が 向上します。OCPに従うことで、開発者は、基礎となるコードを変更することなく、新しい要件に対応するために、既存のコンポーネントを拡張することができます。これにより、新たなバグを発生させたり、既存の機能を破壊したりするリスクを低減することができます。さらに、各コンポーネントの動作が明確に定義されているため、あるコンポーネントへの変更 がシステムの残りの部分にどのような影響を及ぼすかを容易に把握することができます。

結論として、OCPはソフトウェアの複雑さを軽減し、テストの容易さを向上させ、変更の容易さを改善するのに役立ちま す。OCPに従うことで、開発者は理解、テスト、および変更が容易で、より保守性と拡張性の高いソフトウ ェアを書くことができるようになります。

コードはドウダ?

コードの説明

税金と送料の計算の責任を2つの別々のクラスに分離することで、コードの保守、テスト、将来の拡張を容易にしているのだ。

  • Customer クラスは顧客だよ。name、address、age の 3 つのインスタンス変数を持つ値オブジェクトだよ。
  • TaxCalculatorクラスは税額を計算するよ。
  • ShippingCostCalculator クラスは送料を計算するよ。

オープン・クローズドの原則(OCP)をJavaで書くと?

class Customer {
    private String name;
    private String address;
    private int age;
    
    public Customer(String name, String address, int age) {
        this.name = name;
        this.address = address;
        this.age = age;
    }
    
    public String getName() {
        return name;
    }
    
    public String getAddress() {
        return address;
    }
    
    public int getAge() {
        return age;
    }
}

class TaxCalculator {
    public static double calculateTax(double amount) {
        // code to calculate tax
        return amount * 0.10;
    }
}

class ShippingCostCalculator {
    public static double calculateShippingCost(double weight, double distance) {
        // code to calculate shipping cost
        return weight * distance * 0.50;
    }
}

Javaの現実的なコード

Javaだと継承ポリモーフィズムを用いることでOCPを実現することができる。

クラスは、既存のコードを変更することなく、新しい要件に対応するために拡張することができる。

新しい機能を追加する時は、サブクラスがオーバーライドできるメソッドを持つベースクラスを作成することでOCPの原則に沿うものができる。

abstract class Shape {
    abstract double area();
}

class Circle extends Shape {
    private double radius;

    Circle(double radius) {
        this.radius = radius;
    }

    @Override
    double area() {
        return Math.PI * radius * radius;
    }
}

class Rectangle extends Shape {
    private double width;
    private double height;

    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }

    @Override
    double area() {
        return width * height;
    }
}

class Triangle extends Shape {
    private double base;
    private double height;

    Triangle(double base, double height) {
        this.base = base;
        this.height = height;
    }

    @Override
    double area() {
        return 0.5 * base * height;
    }
}

class AreaCalculator {
    static double calculateArea(Shape[] shapes) {
        double area = 0;
        for (Shape shape : shapes) {
            area += shape.area();
        }
        return area;
    }
}

オープン・クローズドの原則(OCP)をGoで書くと?

package main

func calculateTax(amount float64) float64 {
    // code to calculate tax
    return amount * 0.10
}

func calculateShippingCost(weight float64, distance float64) float64 {
    // code to calculate shipping cost
    return weight * distance * 0.50
}

GO の現実的なコード

Goだと、インターフェイスを使用することでOCPを実現することができる。

Goのインターフェイスは型が実装するメソッドのセットを定義するが、それらのメソッドの実装はインターフェイスを変更することなく変更することができる。

これは、たとえば「形状のインタフェース」を作成し、異なる形状(円、四角など)ごと実装することができるといものでアール。

package main

import (
	"fmt"
)

// Shapeインターフェースは、すべてのShapeが実装する「Area()」を定義。
type Shape interface {
	Area() float64
}

// Circle型:Areaメソッド
type Circle struct {
	Radius float64
}

// Shapeインターフェースを変更することなく実装を追加できる
func (c Circle) Area() float64 {
	return 3.14 * c.Radius * c.Radius
}

// Square型:Areaメソッド
type Square struct {
	Side float64
}

// Shapeインターフェースを変更することなく実装を追加できる
func (s Square) Area() float64 {
	return s.Side * s.Side
}

// Shapeインターフェース型を持つShapeCalculator型
type ShapeCalculator struct {
	Shapes []Shape
}

//  Shapes スライス内のすべての形状の総面積を返す。
func (sc ShapeCalculator) TotalArea() float64 {
	var total float64
	for _, shape := range sc.Shapes {
		total += shape.Area()
	}
	return total
}

func main() {
	// Shapeインターフェース値のスライスを作成する。
	shapes := []Shape{
		Circle{Radius: 5},
		Square{Side: 10},
	}

	// すべての図形の総面積を計算する
	calculator := ShapeCalculator{Shapes: shapes}
	total := calculator.TotalArea()
	fmt.Println("Total area:", total)
}

オープン・クローズドの原則(OCP)をClojureで書くと?

(defn calculate-tax [amount]
  (* amount 0.10))

(defn calculate-shipping-cost [weight distance]
  (* weight distance 0.50))

オープン・クローズドの原則(OCP)をPython で書くと?

class Customer:
    def __init__(self, name, address, age):
        self.name = name
        self.address = address
        self.age = age
        
    def get_name(self):
        return self.name
    
    def get_address(self):
        return self.address
    
    def get_age(self):
        return self.age

def calculate_tax(amount):
    # code to calculate tax
    return amount * 0.10

def calculate_shipping_cost(weight, distance):
    # code to calculate shipping cost
    return weight * distance * 0.50

コメントする