Kotlin SOLID の原則

Kotlin SOLID の原則

Kotlin SOLID の原則

Kotlin 開発者の多くは SOLID の原則を完全には理解していませんし、たとえ理解していても、なぜそれを使用するのかわかりません。すべての詳細を学ぶ準備はできていますか?

導入

Kotlin 愛好家の皆さん、こんにちは。私の新しい記事へようこそ。今日は Kotlin の SOLID 原則について話します。まず、SOLID 原則とは何なのか、また、それが何に使用されるのか、例を示して説明します。

SOLID原則とは何ですか?

SOLID は、保守可能、スケーラブル、堅牢なソフトウェアの作成に役立つ5 つの設計原則の頭字語です。Robert C. Martin は、プログラマーが高品質のコードを作成できるように、これらの原則を導入しましたSOLID はもともとオブジェクト指向プログラミングを目的としていましたが、Kotlin などの他の言語にも適用できます。これらの原則は、クリーンなコードを促進し、ソフトウェア設計を改善することを目的としていますSOLID の原則は次のとおりです。

  • 単一責任の原則
  • 開閉原理
  • リスコフ置換原理
  • インターフェース分離原理
  • 依存関係逆転の原則
    さて、準備ができたら、正しい使用法と違反の例を示しながら、これらの原則を詳しく見てみましょう。

単一責任の原則

単一責任原則 (SRP) は、オブジェクト指向プログラミングにおける SOLID プログラミング原則の一部です。これは、特定のクラスの変更された目的は 1 つだけである必要があることを示します。** これは、クラスが持つ責任または仕事は 1 つだけである必要があることを意味します。SRP は、クラスと関数を整理して理解しやすく保つことで、維持するのに役立ちます。**クラスに複数の責任がある場合、それらの責任がクラスの他のタスクやジョブに誤って影響を及ぼし、予期しない動作、バグ、およびメンテナンスコストの増加につながる可能性があります。

違反とその正しい使い方を見てみましょう。

違反:

// Single Responsibility Principle Violation
// In this example the System class is trying to handle many different situation at the same time. 
// This approach can cause major problems in the future.
class SystemManager {
    
    
    fun addUser(user: User) {
    
     }
    fun deleteUser(user: User) {
    
     }
    fun sendNotification(notification:String) {
    
    }
    fun sendEmail(user: User, email: String) {
    
    }
}

単一責任原則の違反
この例では、システム クラスが同じ場所で多くの異なる状況を処理しようとします。このアプローチは将来的に大きな問題を引き起こす可能性があります。

正しい使い方:

// Single Responsibility Principle Correct Usage:
// As seen in this example, we divided our System class into specific parts
// And placed the functions in their respective classes.

class MailManager() {
    
    
    fun sendEmail(user: User, email: String) {
    
    }
}

class NotificationManager() {
    
    
    fun sendNotification(notification: String) {
    
    }
}

class UserManager {
    
    
    fun addUser(user: User) {
    
    }
    fun deleteUser(user: User) {
    
    }
}

単一責任の原則を正しく使用する
この例に示すように、System クラスを特定のセクションに分割し、関数をそれぞれのクラスに配置します。

開閉原理

オープン/クローズ原則は、クラス、モジュール、関数、およびその他のソフトウェア エンティティは拡張に対してはオープンであるが、変更に対してはクローズされるべきであるというオブジェクト指向設計のルールです。これは、元のコードを変更せずにクラスに新しいコンテンツを追加できることを意味します。したがって、クラス自体を変更しなくても、既存のクラスを使用して新しい機能を追加する新しいコードを作成できます。こうすることで、コードの保守と再利用が容易になります。

違反とその正しい使い方を見てみましょう。

違反:

// Open/Closed Principle Violation
// In this example, when we try to add something new to our class,
// we have to rewrite our existing code, which can cause problems later on.
class Shape(val type: String, val width: Double, val height: Double)

fun calculateArea(shape: Shape): Double {
    
    
    if (shape.type == "rectangle") {
    
    
        return shape.width * shape.height
    } else if (shape.type == "circle") {
    
    
        return Math.PI * shape.width * shape.width
    }
    return 0.0
}

オープンクローズ原則の違反
この例では、クラスに何か新しいものを追加しようとすると、既存のコードを書き直す必要があり、後で問題が発生する可能性があります。

正しい使い方:

// Open/Closed Principle Correct Usage
// As in correct usage, instead of changing the class itself,
// we wrote new classes using our existing class 
// and implemented our functions under new classes.

interface Shape {
    
    
    fun area(): Double
}

class Rectangle(val width: Double, val height: Double) : Shape {
    
    
    override fun area() = width * height
}

class Circle(val radius: Double) : Shape {
    
    
    override fun area() = Math.PI * radius * radius
}

fun calculateArea(shape: Shape) = shape.area()

オープンとクローズの原理の正しい使い方 正しい
使い方によれば、クラス自体を変更するのではなく、既存のクラスを使用して新しいクラスを作成し、新しいクラスの下に関数を実装します。

リスコフ置換原理

リスコフ置換原則は、オブジェクト指向プログラミングにおける重要なルールです。特定の型のオブジェクトを処理できるプログラムがある場合は、そのオブジェクトのどのサブタイプでも問題なく使用できるはずだと書かれています。これは、メイン クラスのすべてのメソッドとプロパティは、何も変更せずにすべてのサブクラスでも使用できる必要があることを意味します。

違反とその正しい使い方を見てみましょう。

違反:

// Liskov Substitution Principle Violation:
// As we saw in this example, the method we wrote in our main class should work properly in its subclasses according to the Liskov principle, 
// but when our subclass inherited from our superclass, our fly method did not work as expected.

open class Bird {
    
    
    open fun fly() {
    
    }
}

class Penguin : Bird() {
    
    
    override fun fly() {
    
    
        print("Penguins can't fly!")
    }
}

リスコフ置換原則の違反
この例でわかるように、メインクラスで作成したメソッドはリスコフ原則に従ってサブクラスで正常に動作するはずですが、サブクラスがスーパークラスから継承すると、fly メソッドは正常に動作しません。期待される。

正しい使い方:

// Liskov Substitution Principle Correct Usage
// As you can see in this example, all the things we write in the superclass will be valid in the subclasses, 
// because we have implemented the method that is not valid for subclasses by creating an interface and implementing it where we need it.

open class Bird {
    
    
    // common bird methods and properties
}

interface IFlyingBird {
    
    
    fun fly(): Boolean
}

class Penguin : Bird() {
    
    
    // methods and properties specific to penguins
}

class Eagle : Bird(), IFlyingBird {
    
    
    override fun fly(): Boolean {
    
    
        return true
    }
}

リスコフ置換原則の正しい使用法
この例でわかるように、スーパークラスに記述したものはすべてサブクラスでも有効になります。これは、インターフェイスを作成し、必要なときにそのインターフェイスを実装することによって行われるためです。サブクラスに対して有効です。

インターフェース分離原理

インターフェース分離原則とは、コンピュータプログラムを作成するための規則です。プログラムの異なる部分を作るとき、同じように作ってはいけない、ということです。代わりに、プログラムの他の部分が必要のないものに依存する必要がないように、プログラムをより小さく、より具体的にする必要があります。これにより、各部分が必要なことだけを実行するため、変更と保守が容易なコードを作成できます。

違反とその正しい使い方を見てみましょう。

違反:

// Interface Segregation Principle Violation
// When we look at our example, we see that the interface we created contains many methods.
// If we do everything inside a common interface, we may have made unnecessary use in the places that implement our interface.
// Instead, we can divide our system into smaller interface parts.

interface Animal {
    
    
    fun swim()
    fun fly()
}

class Duck : Animal {
    
    
    override fun swim() {
    
    
        println("Duck swimming")
    }

    override fun fly() {
    
    
        println("Duck flying")
    }
}

class Penguin : Animal {
    
    
    override fun swim() {
    
    
        println("Penguin swimming")
    }

    override fun fly() {
    
    
        throw UnsupportedOperationException("Penguin cannot fly")
    }
}

インターフェイス分離原則の違反
この例を見ると、作成したインターフェイスに多くのメソッドが含まれていることがわかりました。すべてをパブリック インターフェイス内で実行すると、インターフェイスが実装されている場所で不必要な使用が行われる可能性があります。代わりに、システムをより小さなインターフェイス部分に分割できます。

正しい使い方:

// Interface Segregation Principle Correct Usage
// As we saw in the correct usage example, dividing the system into smaller interfaces and using them where we needed them made it much easier to change the system in the future.

interface CanSwim {
    
    
    fun swim()
}

interface CanFly {
    
    
    fun fly()
}

class Duck : CanSwim, CanFly {
    
    
    override fun swim() {
    
    
        println("Duck swimming")
    }

    override fun fly() {
    
    
        println("Duck flying")
    }
}

class Penguin : CanSwim {
    
    
    override fun swim() {
    
    
        println("Penguin swimming")
    }
}

インターフェイス分離の原則を正しく使用する
正しい使用例で見たように、システムを小さなインターフェイスに分割し、必要な場所で使用すると、将来のシステム変更が容易になります。

依存関係逆転の原則

依存性反転原則は、高レベルのモジュールが低レベルのモジュールに依存すべきではないが、両方とも抽象化に依存すべきであると規定する SOLID 原則です。これは、クラスが具体的な実装ではなく抽象化に依存する必要があることを意味します。DIP の背後にある考え方は、コンポーネントを相互に分離することです。これにより、コードがよりモジュール化され、テストと保守が容易になります。

違反とその正しい使い方を見てみましょう。

違反:

// Dependency Inversion Principle Violation
// As we can see in this example, each of our payment methods is processed separately in our Service class in a hard code way.
// Instead of a hard code implementation, the system needed to be DEPEND to an abstract structure.

class PaymentService {
    
    
    private val paymentProcessorPaypal = PaypalPaymentProcessor()
    private val paymentProcessorStripe = StripePaymentProcessor()

    fun processPaymentWithPaypal(amount: Double): Boolean {
    
    
        return paymentProcessorPaypal.processPayment(amount)
    }

    fun processPaymentWithStripe(amount: Double): Boolean {
    
    
        return paymentProcessorStripe.processPayment(amount)
    }
}

class PaypalPaymentProcessor {
    
    
    fun processPayment(amount: Double): Boolean {
    
    
        // Process payment via Paypal API
        return true
    }
}

class StripePaymentProcessor {
    
    
    fun processPayment(amount: Double): Boolean {
    
    
        // Process payment via Stripe API
        return true
    }
}


fun main() {
    
    
    val paymentService = PaymentService()
    println(paymentService.processPaymentWithPaypal(50.0)) // Process payment via Paypal API
    println(paymentService.processPaymentWithStripe(50.0)) // Process payment via Stripe API
}

依存関係逆転原則の違反
この例でわかるように、各支払い方法はサービス クラスで個別に処理できるようにハードコーディングされています。システムは、ハードコードされた実装ではなく、抽象構造に依存する必要があります。

正しい使い方:

// In the correct usage example, we did not have to implement hard code about our payment methods in our Service class,
// because we set up an abstract structure with the interface that we created.

interface PaymentProcessor {
    
    
    fun processPayment(amount: Double): Boolean
}

class PaypalPaymentProcessor : PaymentProcessor {
    
    
    override fun processPayment(amount: Double): Boolean {
    
    
        // Process payment via Paypal API
        return true
    }
}

class StripePaymentProcessor : PaymentProcessor {
    
    
    override fun processPayment(amount: Double): Boolean {
    
    
        // Process payment via Stripe API
        return true
    }
}

class PaymentService(private val paymentProcessor: PaymentProcessor) {
    
    
    fun processPayment(amount: Double): Boolean {
    
    
        return paymentProcessor.processPayment(amount)
    }
}

fun main() {
    
    
    val paymentProcessor = PaypalPaymentProcessor()
    val paymentService = PaymentService(paymentProcessor)
    println(paymentService.processPayment(50.0)) // Process payment via Paypal API
}

正しい使用例では、作成したインターフェイスで抽象構造を設定しているため、サービス クラスに支払い方法に関するハードコードを実装する必要はありません。

結論は

したがって、Kotlin で保守可能、スケーラブル、効率的なソフトウェアを作成するには、SOLID 原則が不可欠です。Kotlin の独自の機能と構造を使用すると、開発者はこれらのガイドラインに従ったモジュール式の疎結合システムを設計できます。SOLID 原則に従うと、コードのテスト容易性が向上するだけでなく、継続的な改善とベスト プラクティスの文化も奨励されます。最終的に、これらの原則を Kotlin 開発に採用すると、効率的に保守でき、変化するニーズに適応できる高品質のソフトウェアが得られます。

ここに画像の説明を挿入

参考

[Kotlin 言語] https://kotlinlang.org/
[Kotlin の SOLID 原則] https://proandroiddev.com/solid-design-principles-in-kotlin-79100c670df1
[SOLD 原則: Kotlin のやり方] https:// Medium.com/the-android-caf%C3%A9/solid-principles-the-kotlin-way-ff717c0d60da
[SOLD 原則と Kotlin の例] https://codersee.com/solid-principles-with-kotlin-examples/
[SOLID 原則を採用し、クリーンで保守可能なコードを作成する] https://bootcamp.uxdesign.cc/adopting-solid-principles-for-clean-and-maintainable-code-with-kotlin-51e615c6b315

おすすめ

転載: blog.csdn.net/u011897062/article/details/130879774