ソフトウェア開発では、コードのメンテナンス、拡張、柔軟性がプロジェクトの長期的な成功にとって重要です。 SOLID 原則は、開発者が理解しやすく、変更し、拡張しやすいコードを作成できるように策定されました。この記事では、SOLID の 5 つの原則のそれぞれについて、および Java での実際の例とともにその使用方法について説明します。
単一責任原則 (SRP) は、クラスが変更する理由は 1 つだけである必要があること、つまり、クラスはシステム内で単一の責任を持つ必要があることを確立します。
// Antes de aplicar o SRP class ProductService { public void saveProduct(Product product) { // Lógica para salvar o produto no banco de dados } public void sendEmail(Product product) { // Lógica para enviar um email sobre o produto } }
// Após aplicar o SRP class ProductService { public void saveProduct(Product product) { // Lógica para salvar o produto no banco de dados } } class EmailService { public void sendEmail(Product product) { // Lógica para enviar um email sobre o produto } }
この例では、製品をデータベースに保存する責任と、その製品に関する電子メールを送信する責任を分離しています。これにより、電子メール送信の変更が製品保存ロジックに影響を与えなくなるため、将来の変更が容易になります。
オープン/クローズ原則 (OCP) は、ソフトウェア エンティティ (クラス、モジュール、関数など) は拡張に対してはオープンであるが、変更に対してはクローズされるべきであることを示唆しています。これは、抽象化と継承を使用することで実現されます。
// Exemplo inicial violando o OCP class AreaCalculator { public double calculateArea(Rectangle[] rectangles) { double area = 0; for (Rectangle rectangle : rectangles) { area += rectangle.width * rectangle.height; } return area; } }
// Exemplo após aplicar o OCP interface Forma { double calculateArea(); } class Rectangle implements Forma { private double width; private double height; public Rectangle(double width, double height) { this.width = width; this.height = height; } @Override public double calculateArea() { return width * height; } } class AreaCalculator { public double calculateArea(Forma [] formas) { double area = 0; for (Forma formas: formas) { area += forma.calculateArea(); } return area; } }
この 2 番目の例では、当初、AreaCalculator クラスは Rectangle クラスに直接依存していました。つまり、円や三角形など、別の種類の図形を追加したい場合は、AreaCalculator クラスを変更する必要があり、OCP に違反します。 Shape インターフェイスの作成により、AreaCalculator クラスは、既存のコードを変更せずに新しい幾何学的形状を受け取ることができるようになりました。
リスコフ置換原則 (LSP) では、スーパークラスのオブジェクトは、システムの整合性に影響を与えることなく、そのサブクラスのオブジェクトで置き換え可能でなければならないと規定されています。言い換えれば、サブクラスの動作はスーパークラスの動作と一致している必要があります。
// Classe base class Bird { public void fly() { // Método padrão que imprime "Flying" System.out.println("Flying"); } } // Classe derivada que viola o LSP class Duck extends Bird { @Override public void fly() { // Sobrescrita que imprime "Ducks cannot fly" System.out.println("Ducks cannot fly"); } }
問題: Duck クラスは、fly() メソッドをオーバーライドして「アヒルは飛べない」と表示するため、Bird 基本クラスで定義されているデフォルトの動作、つまりすべての鳥が飛ぶ (「飛ぶ」) を変更します。これは LSP に違反します。Bird オブジェクトまたはそのサブクラスが飛行することを期待するコードは、Duck では正しく動作しません。Duck は飛行しないことがすでにわかっています。
// Classe derivada que respeita o LSP interface Bird { void fly(); } class Eagle implements Bird { @Override public void fly() { System.out.println("Flying like an Eagle"); } } class Duck implements Bird { @Override public void fly() { throw new UnsupportedOperationException("Ducks cannot fly"); } }
このアプローチを使用すると、Bird インターフェースによって設定された期待を裏切ることなく、Bird が期待される場所で Eagle と Duck を交換できます。 Duck によってスローされた例外は、コード内で予期せぬ問題を引き起こす可能性のある方法でスーパークラスの動作を変更することなく、アヒルが飛行しないことを明示的に伝えます。
インターフェイス分離原則 (ISP) は、クラスのインターフェイスは、それを使用するクライアントに固有である必要があることを示唆しています。これにより、クライアントが使用しないメソッドの実装を必要とする「ファット」インターフェイスが回避されます。
// Exemplo antes de aplicar o ISP interface Worker { void work(); void eat(); void sleep(); } class Programmer implements Worker { @Override public void work() { // Lógica específica para programar } @Override public void eat() { // Lógica para comer } @Override public void sleep() { // Lógica para dormir } }
// Exemplo após aplicar o ISP interface Worker { void work(); } interface Eater { void eat(); } interface Sleeper { void sleep(); } class Programmer implements Worker, Eater, Sleeper { @Override public void work() { // Lógica específica para programar } @Override public void eat() { // Lógica para comer } @Override public void sleep() { // Lógica para dormir } }
この例では、Worker インターフェイスをより小さなインターフェイス (Work、Eat、Sleep) に分割して、それらを実装するクラスが必要なメソッドのみを持つようにしています。これにより、クラスが自分たちに関係のないメソッドを実装する必要がなくなり、コードの明瞭さと一貫性が向上します。
依存関係逆転原則 (DIP) は、高レベルのモジュール (主要なビジネス ルールを実装するビジネス クラスやアプリケーション クラスなど) が低レベルのモジュール (外部データや外部データへのアクセスなどのインフラストラクチャ クラス) に依存すべきではないことを示唆しています。高度な操作をサポートするサービス)。どちらも抽象化に依存する必要があります。
// Exemplo antes de aplicar o DIP class BackendDeveloper { public void writeJava() { // Lógica para escrever em Java } } class Project { private BackendDeveloper developer; public Project() { this.developer = new BackendDeveloper(); } public void implement() { developer.writeJava(); } }
// Exemplo após aplicar o DIP interface Developer { void develop(); } class BackendDeveloper implements Developer { @Override public void develop() { // Lógica para escrever em Java } } class Project { private Developer developer; public Project(Developer developer) { this.developer = developer; } public void implement() { developer.develop(); } }
Project クラスは、具体的な実装 (BackendDeveloper) ではなく抽象化 (Developer) に依存するようになりました。これにより、コードを変更せずに、さまざまなタイプの開発者 (FrontendDeveloper、MobileDeveloper など) を Project クラスに簡単に挿入できるようになります。
SOLID 原則を採用すると、コードの品質が向上するだけでなく、技術スキルが強化され、作業効率が向上し、ソフトウェア開発者としてのキャリアパスも向上します。
以上がSOLID指向の開発の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。