ホームページ  >  記事  >  ウェブフロントエンド  >  Aplicando o Open/Closed Principle com Typescript e Java

Aplicando o Open/Closed Principle com Typescript e Java

王林
王林オリジナル
2024-08-29 14:38:05372ブラウズ

Aplicando o Open/Closed Principle com Typescript e Java

コンセプト

抽象化

オブジェクト指向の概念における抽象化は、クラスが持つ必要がある重要な側面のみを定義する実践です。子クラスを通じて特異性をモデル化できるように、クラスは本質的に不完全かつ不正確である必要があります。したがって、娘クラス、母親クラス、および継承という概念が生じます。

遺産

継承は、親クラスの動作を継承するために、あるクラスが別のクラスを拡張するクラス間の関係を表現したものです。

固体

SOLID は、ロバート C. マーティン (アンクル ボブ) によって提案された、オブジェクト指向プログラミングの 5 つの基本原則を表す頭字語です。ここで彼の記事の詳細を読むことができます。
これらの原則は、コードの構造とメンテナンスを改善し、コードをより柔軟でスケーラブルにし、理解しやすくすることを目的としています。このような原則は、プログラマーがより組織化されたコードを作成し、責任を分割し、依存関係を減らし、リファクタリング プロセスを簡素化し、コードの再利用を促進するのに役立ちます。

オープン/クローズの原則

頭字語の「O」は、「オープン/クローズ原則」を表します。ボブおじさんがこの原則を定義するために使用したフレーズは次のとおりです:

「クラスは拡張のためにオープンされている必要がありますが、変更のためにクローズされている必要があります。」

この原則に従って、クラスまたはオブジェクトの動作を拡張する必要があると感じたときにはいつでもクラス自体を変更する必要がないように、クラスまたはモジュールを汎用的な方法で作成するようにアプリケーションを開発する必要があります。 。ここでの拡張とは、手順の追加や変更とも読み替えられます。

目的は、既存のコードを変更することなく新しい機能を追加できるようにすることです。これにより、バグが発生するリスクが最小限に抑えられ、コードがより保守しやすくなります。

実用化

製品の割引を計算するDiscountCalculatorクラスがあると想像してください。当初は、エレクトロニクスと衣料品の 2 つの製品カテゴリがありました。 OCP (オープン/クローズ原則) を適用せずに始めましょう:

ジャワ

class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public double getPrice() {
        return price;
    }
}

class DiscountCalculator {
    public double calculateDiscount(Product product) {
        if (product.getName().equals("Electronics")) {
            return product.getPrice() * 0.9; // 10% de desconto
        } else if (product.getName().equals("Clothing")) {
            return product.getPrice() * 0.8; // 20% de desconto
        }
        return product.getPrice();
    }
}

public class Main {
    public static void main(String[] args) {
        Product electronics = new Product("Electronics", 100);
        Product clothing = new Product("Clothing", 50);

        DiscountCalculator calculator = new DiscountCalculator();

        System.out.println(calculator.calculateDiscount(electronics)); // 90
        System.out.println(calculator.calculateDiscount(clothing)); // 40
    }
}

タイプスクリプト

class Product {
    private _name: string;
    private _price: number;

    constructor(name: string, price: number) {
        this._name = name;
        this._price = price;
    }

    public get name() { return this.name };

    public set name(value: string) { this.name = value };

    public get price() { return this.price };

    public set price(value: number) { this.price = value };
}

class DiscountCalculator {
    public calculateDiscount(product: Product): number {
        if (product.name === 'Electronics') {
            return product.price * 0.9; // 10% de desconto
        } else if (product.name === 'Clothing') {
            return product.price * 0.8; // 20% de desconto
        }
        return product.price;
    }
}

const electronics = new Product('Electronics', 100);
const clothing = new Product('Clothing', 50);

const calculator = new DiscountCalculator();

console.log(calculator.calculateDiscount(electronics)); // 90
console.log(calculator.calculateDiscount(clothing)); // 40

OCP を適用しない場合の問題

カプセル化違反: 新しい製品タイプで異なる割引が必要になるたびに、if に新しい条件を含めて、calculateDiscount メソッドを変更する必要があります。

メンテナンスの難しさ: if/else やスイッチが多すぎるメソッドが増加すると、メンテナンスとテストが困難になります。

バグが導入されるリスク: メソッドを変更すると、そのメソッドに依存するコードの他の部分にバグが導入される可能性があります。

修正方法は?

次に、コードをリファクタリングしてオープン/クローズ原則を適用し、既存のコードを変更せずに新しいタイプの割引を追加できるようにしましょう。

ジャワ

class Product {
    private String name;
    private double price;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }
}

interface DiscountStrategy {
    double calculate(Product product);
}

class ElectronicsDiscount implements DiscountStrategy {
    @Override
    public double calculate(Product product) {
        return product.getPrice() * 0.9; // 10% de desconto
    }
}

class ClothingDiscount implements DiscountStrategy {
    @Override
    public double calculate(Product product) {
        return product.getPrice() * 0.8; // 20% de desconto
    }
}

class NoDiscount implements DiscountStrategy {
    @Override
    public double calculate(Product product) {
        return product.getPrice();
    }
}

class DiscountCalculator {
    private DiscountStrategy discountStrategy;

    public DiscountCalculator(DiscountStrategy discountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public double calculateDiscount(Product product) {
        return discountStrategy.calculate(product);
    }
}

public class Main {
    public static void main(String[] args) {
        Product electronics = new Product("Electronics", 100);
        Product clothing = new Product("Clothing", 50);
        Product books = new Product("Books", 30);

        DiscountCalculator electronicsDiscount = new DiscountCalculator(new ElectronicsDiscount());
        DiscountCalculator clothingDiscount = new DiscountCalculator(new ClothingDiscount());
        DiscountCalculator booksDiscount = new DiscountCalculator(new NoDiscount());

        System.out.println(electronicsDiscount.calculateDiscount(electronics)); // 90
        System.out.println(clothingDiscount.calculateDiscount(clothing)); // 40
        System.out.println(booksDiscount.calculateDiscount(books)); // 30
    }
}

タイプスクリプト

class Product {
    private _name: string;
    private _price: number;

    constructor(name: string, price: number) {
        this._name = name;
        this._price = price;
    }

    public get name() { return this.name };

    public set name(value: string) { this.name = value };

    public get price() { return this.price };

    public set price(value: number) { this.price = value };
}

interface DiscountStrategy {
    calculate(product: Product): number;
}

class ElectronicsDiscount implements DiscountStrategy {
    calculate(product: Product): number {
        return product.price * 0.9; // 10% de desconto
    }
}

class ClothingDiscount implements DiscountStrategy {
    calculate(product: Product): number {
        return product.price * 0.8; // 20% de desconto
    }
}

class NoDiscount implements DiscountStrategy {
    calculate(product: Product): number {
        return product.price;
    }
}

class DiscountCalculator {
    private discountStrategy: DiscountStrategy;

    constructor(discountStrategy: DiscountStrategy) {
        this.discountStrategy = discountStrategy;
    }

    public calculateDiscount(product: Product): number {
        return this.discountStrategy.calculate(product);
    }
}

const electronics = new Product('Electronics', 100);
const clothing = new Product('Clothing', 50);
const books = new Product('Books', 30);

const electronicsDiscount = new DiscountCalculator(new ElectronicsDiscount());
const clothingDiscount = new DiscountCalculator(new ClothingDiscount());
const booksDiscount = new DiscountCalculator(new NoDiscount());

console.log(electronicsDiscount.calculateDiscount(electronics)); // 90
console.log(clothingDiscount.calculateDiscount(clothing)); // 40
console.log(booksDiscount.calculateDiscount(books)); // 30

結論

既存のコード ベースを大幅に変更せずに新しい機能や動作を追加する必要がある場合、オープン/クローズの原則を適用することが不可欠です。実際、時間の経過とともに、コード ベースの変更を 100% 回避することは事実上不可能であることがわかりますが、新しい機能を挿入するために変更されるコードの総量を軽減することは可能です。

この原則により、新しい要件を満たすためでも、エラーを修正するためでも、コードは変更に適応しやすくなります。

以上がAplicando o Open/Closed Principle com Typescript e Javaの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。