C#でオープン・クローズドの原則(OCP)を実装する方法
クラス、モジュール、関数といったソフトウェアの構成要素は、「拡張に対して開かれており(Open for Extension)、修正に対して閉じられている(Closed for Modification)」べきです。これが、SOLID設計原則のひとつであるオープン・クローズドの原則(OCP:Open Closed Principle)の核心的な考え方です。
オープン・クローズドの原則とは
定義: オープン・クローズドの原則とは、既存のコードへの変更を最小限に抑えながら、新しい機能を追加できるようにコードを設計・記述すべきという原則です。つまり、できる限り既存コードをそのまま維持しつつ、新機能を「新しいクラス」として追加していけるような設計が求められます。
具体例で理解するOCP
OCP適用前のコード
まずは、原則に従っていないコードを見てみましょう。
using System;
using System.Net.Mail;
namespace SolidPrinciples.Open.Closed.Principle.Before
{
public class Rectangle
{
public int Width { get; set; }
public int Height { get; set; }
}
public class CombinedAreaCalculator
{
public double Area(object[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
if (shape is Rectangle)
{
Rectangle rectangle = (Rectangle)shape;
area += rectangle.Width * rectangle.Height;
}
}
return area;
}
}
public class Circle
{
public double Radius { get; set; }
}
public class CombinedAreaCalculatorChange
{
public double Area(object[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
if (shape is Rectangle)
{
Rectangle rectangle = (Rectangle)shape;
area += rectangle.Width * rectangle.Height;
}
if (shape is Circle)
{
Circle circle = (Circle)shape;
area += (circle.Radius * circle.Radius) * Math.PI;
}
}
return area;
}
}
}
このコードには明確な問題点があります。CombinedAreaCalculatorはis演算子で型を判定し、図形ごとに分岐処理を書いて面積を計算しています。この状態でTriangleなどの新しい図形を追加しようとすると、CombinedAreaCalculatorChangeのようにif文を増やして既存のメソッドを修正する必要が生じます。これは「修正に対して開いた状態」であり、OCPに違反している典型的な例です。
OCP適用後のコード
続いて、オープン・クローズドの原則を適用してリファクタリングしたコードです。
namespace SolidPrinciples.Open.Closed.Principle.After
{
public abstract class Shape
{
public abstract double Area();
}
public class Rectangle : Shape
{
public int Width { get; set; }
public int Height { get; set; }
public override double Area()
{
return Width * Height;
}
}
public class Circle : Shape
{
public double Radius { get; set; }
public override double Area()
{
return Radius * Radius * Math.PI;
}
}
public class CombinedAreaCalculator
{
public double Area(Shape[] shapes)
{
double area = 0;
foreach (var shape in shapes)
{
area += shape.Area();
}
return area;
}
}
}
改善のポイントは以下の3点です。
- 抽象基底クラスShapeの導入: 面積を返す抽象メソッド
Area()を持つShapeクラスを定義し、共通の契約を作ります。 - 各図形が自身の計算ロジックを持つ:
RectangleやCircleはShapeを継承し、それぞれのArea()メソッドをオーバーライドします。 - 計算クラスの汎用化:
CombinedAreaCalculatorはShape型の配列を受け取り、多態性(ポリモーフィズム)によってshape.Area()を呼び出すだけでよくなります。
この設計により、今後Triangleなど新しい図形が必要になった場合でも、Shapeを継承した新しいクラスを追加するだけで対応できます。既存のCombinedAreaCalculatorを一切修正する必要がないため、拡張に対して開かれ、修正に対して閉じられた理想的な状態を実現できています。
-
Java 9でJavaFXを使ってJShellをプログラムから実装する方法
JShellは、サンプル式を対話的に実行できるツールです。通常はコマンドラインから利用しますが、JavaFXアプリケーションの中でプログラム的にJShellを実装することも可能です。その場合、Javaプログラムに以下のパッケージをインポートする必要があります。import jdk.jshell.JShell; import jdk.jshell.SnippetEvent; import jdk.jshell.VarSnippet;これらのクラスの役割は次のとおりです。JShell:評価エンジンの本体。式や文を評価(eval)するためのAPIを提供します。SnippetEvent:評価結果として
-
Tkinterを使って外部プログラムを開く方法を解説
アプリケーションを開発していると、外部のプログラムやアプリケーションと連携する必要が出てくることがあります。システム上のアプリケーションやプログラムを操作するには、Pythonのosモジュールを利用します。この記事では、osモジュールを使って外部プログラムと連携し、ファイルを開く方法を詳しく解説します。まず、filedialogライブラリを使用して、ユーザーが選択したファイルを開くための関数を定義します。次に、選択されたファイルのパスを画面に表示し、osモジュールを使ってそのファイルを実行します。コード例# 必要なライブラリをインポート from tkinter import * from t