C#トップデザインパターン
デザインパターンは、一般的なソフトウェア開発の問題に対する再利用可能なソリューションであり、より効率的で保守性の高い方法でオブジェクト指向コードを構造化し、実装するためのテンプレートを提供します。 これらのツールは、開発者が柔軟でスケーラブルな方法でオブジェクトの作成、構造、および通信に関する問題を解決するのに役立ちます。 デザインパターンは、より良いコードを書くために開発者を導くベストプラクティスの概念として機能します。 ソフトウェア設計における基本原則の1つに、SOLID原則の一部である単一責任原則(SRP)があります。
彼のビデオ"Design Patterns:Design Patterns: Single Responsibility Principle Explained Practically in C# (The S in SOLID)"では、ティム・コーリーが単一責任原則(SRP)を探求し、ソフトウェア設計におけるその重要性を強調するとともに、それを効果的に実装する方法について実践的な洞察を提供しています。 この記事では、彼のビデオからの重要な要点の簡潔な概要を提供し、クリーンで保守可能なコードを作成するSRPの重要性を強調する。
SRPの紹介
ソフトウェア設計において、SOLIDの原則は、保守可能でスケーラブルなコードを作成するために非常に重要です。 また、コードを理解しやすく、テストしやすく、変更しやすくします。 5つの原則-単一責任原則(SRP)、オープン/クローズド原則(OCP)、リスコフ置換原則(LSP)、インターフェース分離原則(ISP)、依存関係逆転原則(DIP)-は、オブジェクト指向設計に不可欠であり、ソリューションをより堅牢にするためにデザインパターンの中で適用することができます。
C#のデザインパターンを適用することで、開発者は一般的な問題をより効果的に解決することができます。 オブジェクトの作成であれ、ツリー構造の定義であれ、シングルインスタンスによる再利用性の確保であれ、デザインパターンはソフトウェアアーキテクチャを強化する定義済みのソリューションを提供します。 ファクトリーメソッド、ビルダー、シングルトンなどのパターンは、柔軟で再利用可能なソリューションを提供し、動作パターンや構造パターンは、複雑さを管理し、システム内のコミュニケーションを改善するのに役立ちます。 これらのパターンを学び活用することで、開発者は保守や拡張が容易なシステムを構築することができます。
TimはSRPの概念について説明し、開発者がコードをベストプラクティスに準拠させることが極めて重要であることを強調します。 SRPでは、クラスは1つの責任または変更理由のみを持つべきであると述べています。 この原則は、クリーンで保守性が高く、スケーラブルなコードを維持するのに役立ちます。
デモコードの概要
TimはC#で簡単なコンソールアプリケーションをセットアップし、ユーザーの姓名を尋ね、これらの名前を検証し、ユーザー名を生成する。 最初の実装はSRPに違反しており、この原則を守るためにコードをリファクタリングする方法を示す絶好の機会となっています。
SRPの説明
Timは、初期クラス内の複数の責任を強調することで、SRPを説明します:
1.ユーザーインタラクション: ウェルカムメッセージやプロンプトの処理。 2.データキャプチャ:ユーザーの姓名をキャプチャすること。 3.バリデーション:入力名を検証します。 4.ユーザー名生成:入力された名前からユーザー名を生成します。
これらの責任はそれぞれ、SRPに違反してクラスを変更する異なる理由を表しています。
SRPを遵守するためのリファクタリング
Timは、各責任を独自のクラスに抽出することによって、SRPに従うようにコードをリファクタリングする方法を示します。 このアプローチにより、各クラスの変更理由が1つになり、コードがモジュール化され、保守が容易になります。
実用的な例
ティムは、リファクタリングの実践的な例を提供します:
using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to my application");
Console.Write("Enter your first name: ");
string firstName = Console.ReadLine();
Console.Write("Enter your last name: ");
string lastName = Console.ReadLine();
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
{
Console.WriteLine("You did not give us valid information!");
Console.ReadLine();
return;
}
var userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower();
Console.WriteLine($"Your username is {userName}");
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}using System;
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Welcome to my application");
Console.Write("Enter your first name: ");
string firstName = Console.ReadLine();
Console.Write("Enter your last name: ");
string lastName = Console.ReadLine();
if (string.IsNullOrWhiteSpace(firstName) || string.IsNullOrWhiteSpace(lastName))
{
Console.WriteLine("You did not give us valid information!");
Console.ReadLine();
return;
}
var userName = $"{firstName.Substring(0, 1)}{lastName}".ToLower();
Console.WriteLine($"Your username is {userName}");
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
}リファクタリング ステップバイステップ
ステップ 1: StandardMessages クラスの作成
まず、Timはユーザーに表示される標準的なメッセージを処理するクラスを作成します。 このクラスでは、ウェルカムメッセージとエンドメッセージを管理します。
public class StandardMessages
{
public static void WelcomeMessage()
{
Console.WriteLine("Welcome to my application");
}
public static void EndApplication()
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static void ShowValidationErrorMessage()
{
Console.WriteLine("You did not give us valid information!");
}
}public class StandardMessages
{
public static void WelcomeMessage()
{
Console.WriteLine("Welcome to my application");
}
public static void EndApplication()
{
Console.WriteLine("Press enter to close...");
Console.ReadLine();
}
public static void ShowValidationErrorMessage()
{
Console.WriteLine("You did not give us valid information!");
}
}Program クラスで、Console.WriteLine と Console.ReadLine の直接呼び出しを StandardMessages クラスのメソッドの呼び出しに置き換えてください:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
// Other code...
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
// Other code...
StandardMessages.EndApplication();
}
}ステップ 2: PersonDataCapture クラスを作成する
次に、Timは人物の姓と名をキャプチャするクラスを作成します。 このクラスはユーザー入力を収集し、Person オブジェクトを返します。
public class PersonDataCapture
{
public static Person Capture()
{
Person output = new Person();
Console.Write("Enter your first name: ");
output.FirstName = Console.ReadLine();
Console.Write("Enter your last name: ");
output.LastName = Console.ReadLine();
return output;
}
}public class PersonDataCapture
{
public static Person Capture()
{
Person output = new Person();
Console.Write("Enter your first name: ");
output.FirstName = Console.ReadLine();
Console.Write("Enter your last name: ");
output.LastName = Console.ReadLine();
return output;
}
}ステップ 3: Person クラスの作成
また、ユーザーの姓と名を保持する Person クラスも必要です。
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
}Program クラスで、ユーザー入力を直接処理する部分を PersonDataCapture.Capture.Capture の呼び出しに置き換えます:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
// Other code...
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
// Other code...
StandardMessages.EndApplication();
}
}ステップ 4: PersonValidator クラスを作成する
次に、Timは人物の姓と名のバリデーションを処理するクラスを作成します。 このクラスは、名前にヌルや空白がないことを確認する責任があります。
public class PersonValidator
{
public static bool Validate(Person person)
{
if (string.IsNullOrWhiteSpace(person.FirstName))
{
StandardMessages.ShowValidationErrorMessage("first name");
return false;
}
if (string.IsNullOrWhiteSpace(person.LastName))
{
StandardMessages.ShowValidationErrorMessage("last name");
return false;
}
return true;
}
}public class PersonValidator
{
public static bool Validate(Person person)
{
if (string.IsNullOrWhiteSpace(person.FirstName))
{
StandardMessages.ShowValidationErrorMessage("first name");
return false;
}
if (string.IsNullOrWhiteSpace(person.LastName))
{
StandardMessages.ShowValidationErrorMessage("last name");
return false;
}
return true;
}
}Program クラスで、検証コードを PersonValidator.Validate の呼び出しに置き換えます:
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
if (!PersonValidator.Validate(user))
{
StandardMessages.EndApplication();
return;
}
// Other code...
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
if (!PersonValidator.Validate(user))
{
StandardMessages.EndApplication();
return;
}
// Other code...
StandardMessages.EndApplication();
}
}ステップ 7: AccountGenerator クラスを作成する
Timは、ユーザー名生成とアカウント作成ロジックを新しいAccountGeneratorクラスに移動します。
1.AccountGeneratorクラスの作成:
このクラスには、ユーザー名を生成し、アカウント作成をシミュレートするロジックが含まれています。
public class AccountGenerator { public static void CreateAccount(Person user) { string username = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower(); Console.WriteLine($"Your username is: {username}"); } }public class AccountGenerator { public static void CreateAccount(Person user) { string username = $"{user.FirstName.Substring(0, 1)}{user.LastName}".ToLower(); Console.WriteLine($"Your username is: {username}"); } }
1.メインクラスの更新:
- メイン・クラスでアカウントを作成するために AccountGenerator を呼び出します。
class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();
}
}class Program
{
static void Main(string[] args)
{
StandardMessages.WelcomeMessage();
Person user = PersonDataCapture.Capture();
bool isUserValid = PersonValidator.Validate(user);
if (!isUserValid)
{
StandardMessages.EndApplication();
return;
}
AccountGenerator.CreateAccount(user);
StandardMessages.EndApplication();
}
}
要約と結論
この結びのセクションでは、Tim Coreyがデモコードのリファクタリングプロセスを通して、単一責任原則(SRP)の利点と実装を要約します。 彼は、アプリケーションをより小さく、焦点を絞ったクラスに分割することの利点を強調しています。
SRPの主な利点
1.簡易コードメンテナンス:
各クラスは、変更が必要な箇所を見つけやすくするために、1つの責任を持っています。 例えば、ユーザーデータ取得ロジックは、PersonDataCaptureの下に明確に配置されます。
- このような構成にすることで、ユーザー検証を変更したい人は誰でもPersonValidatorを確認することがわかるため、理解が簡単になります。
2.読みやすさの向上:
責任の所在を明確に定義することで、主要なプログラムの流れがより読みやすくなります。 コードは現在、明確で連続したアクションのセットのように読めます:
StandardMessages.WelcomeMessage(); Person user = PersonDataCapture.Capture(); bool isUserValid = PersonValidator.Validate(user); if (!isUserValid) { StandardMessages.EndApplication(); return; } AccountGenerator.CreateAccount(user); StandardMessages.EndApplication();StandardMessages.WelcomeMessage(); Person user = PersonDataCapture.Capture(); bool isUserValid = PersonValidator.Validate(user); if (!isUserValid) { StandardMessages.EndApplication(); return; } AccountGenerator.CreateAccount(user); StandardMessages.EndApplication();
3.複雑さを軽減:
少人数制のクラスはコード行数が少なく、理解しやすく保守しやすい傾向があります。
例StandardMessagesクラスのメソッドは簡潔で、ウェルカムメッセージの表示やアプリケーションの終了など、単一の目的を果たします。
public class StandardMessages { public static void WelcomeMessage() { Console.WriteLine("Welcome to my application"); } public static void EndApplication() { Console.WriteLine("Press enter to close..."); Console.ReadLine(); } public static void ShowValidationErrorMessage(string fieldName) { Console.WriteLine($"You did not give us a valid {fieldName}!"); } }public class StandardMessages { public static void WelcomeMessage() { Console.WriteLine("Welcome to my application"); } public static void EndApplication() { Console.WriteLine("Press enter to close..."); Console.ReadLine(); } public static void ShowValidationErrorMessage(string fieldName) { Console.WriteLine($"You did not give us a valid {fieldName}!"); } }
1.コード変更の容易さ:
各クラスの変更理由は1つであるため、新しい要件に応じてコードを修正するのは簡単です。
- 例要件が終了メッセージを変更することである場合、変更はStandardMessages.EndApplicationメソッドでのみ発生します。
2.より良いデバッグとコラボレーション:
小さくてよく定義されたクラスでは、問題の場所を簡単に特定できるため、デバッグが簡単になります。
- 新しい開発者は、各クラスの明確な構造と責任を理解することで、より迅速に参加することができます。
多くのクラスに関する懸念への対処
Timは、SRPを適用するとクラスが多すぎてプロジェクトが煩雑になるという一般的な懸念に対処します:
1.ナビゲーションと理解:
Visual Studioのインテリセンスのようなツールは、複数のクラスを簡単にナビゲートします。 例えば、F12を押すと、メソッドやクラスの定義に直接移動します。
- 小さく管理しやすい部分をたくさん持つことで、大規模なモノリシッククラスに比べて、アプリケーション全体の理解が容易になります。
2.パフォーマンスとストレージ:
- 追加クラスは、最新のストレージとコンピューティング機能を考慮すると、ディスク容量やパフォーマンスに大きな影響を与えません。
3.バランスと過剰:
ティムはバランスを取るようアドバイスしています。 クラスの責任が大きくなりすぎる場合は、変更する理由が複数あるかどうかを検討し、さらに分割する必要があることを示します。
- Visual Studioでクラスを広範囲にスクロールする必要がある場合、サイズが大きすぎて分割が必要になることがあります。
実践的な実装
Timは、特に既存のコードベースにおいて、SRPを徐々に適用することを開発者に奨励しています。 SRPの原則に沿うように、小さな変更や新しいコードから始めてください。 この漸進的なアプローチは、よりスムーズな移行と継続的な改善を保証します。
結論
ティム・コーリーのリファクタリングの例は、単一責任原則(SRP)を遵守することで、よりクリーンで保守性の高いコードが得られることを示しています。 開発者は、責任をより小さく、焦点を絞ったクラスに分割することで、コードベース内の可読性、デバッグ、コラボレーションを向上させることができます。 このSOLIDデザインパターンの基本原則は、ソフトウェア開発におけるより高度な原則とベストプラクティスへの道を開くものです。
より詳細な情報とコード・サンプルについては、ビデオをご覧ください。また、チャンネルでは、デザイン・パターンのビデオをご覧いただけます。

