MK
摩柯社区 - 一个极简的技术知识社区
AI 面试

Kotlin中的设计模式与实现

2023-10-122.5k 阅读

一、单例模式

1.1 概念

单例模式是一种创建型设计模式,它确保一个类仅有一个实例,并提供一个全局访问点。在 Kotlin 中实现单例模式有多种方式,每种方式都有其特点和适用场景。

1.2 饿汉式单例

饿汉式单例在类加载时就创建实例,所以是线程安全的。

object EagerSingleton {
    fun doSomething() {
        println("EagerSingleton is doing something")
    }
}

在 Kotlin 中,使用 object 关键字就可以轻松创建一个饿汉式单例。object 声明的对象在第一次被访问时就会被初始化,并且是线程安全的。

1.3 懒汉式单例

懒汉式单例在第一次使用时才创建实例。在 Kotlin 中,可以通过 by lazy 实现。

class LazySingleton private constructor() {
    companion object {
        val instance: LazySingleton by lazy {
            LazySingleton()
        }
    }

    fun doSomething() {
        println("LazySingleton is doing something")
    }
}

这里 by lazy 会在第一次调用 instance 时才创建 LazySingleton 的实例,并且 by lazy 本身是线程安全的。

1.4 双重检查锁单例

在 Java 中,双重检查锁机制是常用的懒加载且线程安全的单例实现方式。在 Kotlin 中也可以实现类似的效果。

class DoubleCheckedLockingSingleton private constructor() {
    companion object {
        private var instance: DoubleCheckedLockingSingleton? = null

        fun getInstance(): DoubleCheckedLockingSingleton {
            if (instance == null) {
                synchronized(this) {
                    if (instance == null) {
                        instance = DoubleCheckedLockingSingleton()
                    }
                }
            }
            return instance!!
        }
    }

    fun doSomething() {
        println("DoubleCheckedLockingSingleton is doing something")
    }
}

这种方式通过两次检查 instance 是否为 null,并且使用 synchronized 关键字保证线程安全。只有在第一次创建实例时才会进入同步块,提高了性能。

二、工厂模式

2.1 简单工厂模式

简单工厂模式定义了一个工厂类,用于创建产品对象。它将对象的创建和使用分离,使得代码的可维护性和可扩展性增强。

interface Shape {
    fun draw()
}

class Circle : Shape {
    override fun draw() {
        println("Drawing a circle")
    }
}

class Rectangle : Shape {
    override fun draw() {
        println("Drawing a rectangle")
    }
}

class ShapeFactory {
    fun createShape(shapeType: String): Shape? {
        return when (shapeType) {
            "circle" -> Circle()
            "rectangle" -> Rectangle()
            else -> null
        }
    }
}

使用时:

fun main() {
    val factory = ShapeFactory()
    val circle = factory.createShape("circle")
    circle?.draw()
}

简单工厂模式的优点是实现简单,将对象创建逻辑封装在工厂类中。缺点是不符合开闭原则,如果要添加新的产品类型,需要修改工厂类的代码。

2.2 工厂方法模式

工厂方法模式在简单工厂模式的基础上,将工厂类的创建方法抽象成抽象方法,由具体的工厂子类实现。

interface Shape {
    fun draw()
}

class Circle : Shape {
    override fun draw() {
        println("Drawing a circle")
    }
}

class Rectangle : Shape {
    override fun draw() {
        println("Drawing a rectangle")
    }
}

abstract class ShapeFactory {
    abstract fun createShape(): Shape

    fun doDrawing() {
        val shape = createShape()
        shape.draw()
    }
}

class CircleFactory : ShapeFactory() {
    override fun createShape(): Shape {
        return Circle()
    }
}

class RectangleFactory : ShapeFactory() {
    override fun createShape(): Shape {
        return Rectangle()
    }
}

使用时:

fun main() {
    val circleFactory = CircleFactory()
    circleFactory.doDrawing()

    val rectangleFactory = RectangleFactory()
    rectangleFactory.doDrawing()
}

工厂方法模式符合开闭原则,当添加新的产品类型时,只需要创建新的工厂子类,而不需要修改原有工厂类的代码。

2.3 抽象工厂模式

抽象工厂模式提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

interface GUIFactory {
    fun createButton(): Button
    fun createCheckbox(): Checkbox
}

interface Button {
    fun paint()
}

interface Checkbox {
    fun paint()
}

class WindowsGUIFactory : GUIFactory {
    override fun createButton(): Button {
        return WindowsButton()
    }

    override fun createCheckbox(): Checkbox {
        return WindowsCheckbox()
    }
}

class MacGUIFactory : GUIFactory {
    override fun createButton(): Button {
        return MacButton()
    }

    override fun createCheckbox(): Checkbox {
        return MacCheckbox()
    }
}

class WindowsButton : Button {
    override fun paint() {
        println("Painting a Windows button")
    }
}

class WindowsCheckbox : Checkbox {
    override fun paint() {
        println("Painting a Windows checkbox")
    }
}

class MacButton : Button {
    override fun paint() {
        println("Painting a Mac button")
    }
}

class MacCheckbox : Checkbox {
    override fun paint() {
        println("Painting a Mac checkbox")
    }
}

class Application(private val factory: GUIFactory) {
    fun createUI() {
        val button = factory.createButton()
        val checkbox = factory.createCheckbox()
        button.paint()
        checkbox.paint()
    }
}

使用时:

fun main() {
    val windowsApp = Application(WindowsGUIFactory())
    windowsApp.createUI()

    val macApp = Application(MacGUIFactory())
    macApp.createUI()
}

抽象工厂模式使得代码可以根据不同的操作系统或环境创建不同系列的对象,提高了代码的可维护性和可扩展性。

三、策略模式

3.1 概念

策略模式定义了一系列算法,将每个算法封装起来,并使它们可以相互替换。策略模式使得算法的变化独立于使用算法的客户。

3.2 实现

interface PaymentStrategy {
    fun pay(amount: Double)
}

class CreditCardPayment(private val cardNumber: String, private val cvv: String, private val expirationDate: String) : PaymentStrategy {
    override fun pay(amount: Double) {
        println("Paid $amount using credit card $cardNumber")
    }
}

class PayPalPayment(private val email: String) : PaymentStrategy {
    override fun pay(amount: Double) {
        println("Paid $amount using PayPal account $email")
    }
}

class ShoppingCart {
    private val items = mutableListOf<Pair<String, Double>>()
    private var paymentStrategy: PaymentStrategy? = null

    fun addItem(item: String, price: Double) {
        items.add(Pair(item, price))
    }

    fun setPaymentStrategy(strategy: PaymentStrategy) {
        paymentStrategy = strategy
    }

    fun checkout() {
        val total = items.sumOf { it.second }
        paymentStrategy?.pay(total)
    }
}

使用时:

fun main() {
    val cart = ShoppingCart()
    cart.addItem("Laptop", 1000.0)
    cart.addItem("Mouse", 50.0)

    cart.setPaymentStrategy(CreditCardPayment("1234567890123456", "123", "12/25"))
    cart.checkout()

    cart.setPaymentStrategy(PayPalPayment("example@example.com"))
    cart.checkout()
}

在这个例子中,PaymentStrategy 接口定义了支付算法,CreditCardPaymentPayPalPayment 是具体的支付策略实现。ShoppingCart 类通过设置不同的 PaymentStrategy 来实现不同的支付方式。

四、观察者模式

4.1 概念

观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象状态发生变化时,会通知所有观察者对象,使它们能够自动更新。

4.2 实现

interface Observer {
    fun update(message: String)
}

class ConcreteObserver : Observer {
    override fun update(message: String) {
        println("Received message: $message")
    }
}

interface Subject {
    fun registerObserver(observer: Observer)
    fun removeObserver(observer: Observer)
    fun notifyObservers(message: String)
}

class ConcreteSubject : Subject {
    private val observers = mutableListOf<Observer>()

    override fun registerObserver(observer: Observer) {
        observers.add(observer)
    }

    override fun removeObserver(observer: Observer) {
        observers.remove(observer)
    }

    override fun notifyObservers(message: String) {
        observers.forEach { it.update(message) }
    }
}

使用时:

fun main() {
    val subject = ConcreteSubject()
    val observer1 = ConcreteObserver()
    val observer2 = ConcreteObserver()

    subject.registerObserver(observer1)
    subject.registerObserver(observer2)

    subject.notifyObservers("Something has changed")

    subject.removeObserver(observer2)
    subject.notifyObservers("Another change")
}

在这个例子中,Subject 接口定义了注册、移除和通知观察者的方法,ConcreteSubject 是具体的主题实现。Observer 接口定义了更新方法,ConcreteObserver 是具体的观察者实现。

五、装饰器模式

5.1 概念

装饰器模式动态地给一个对象添加一些额外的职责。就增加功能来说,装饰器模式相比生成子类更为灵活。

5.2 实现

interface Coffee {
    fun getDescription(): String
    fun getCost(): Double
}

class SimpleCoffee : Coffee {
    override fun getDescription(): String {
        return "Simple coffee"
    }

    override fun getCost(): Double {
        return 2.0
    }
}

abstract class CoffeeDecorator(private val coffee: Coffee) : Coffee {
    override fun getDescription(): String {
        return coffee.getDescription()
    }

    override fun getCost(): Double {
        return coffee.getCost()
    }
}

class MilkDecorator(private val coffee: Coffee) : CoffeeDecorator(coffee) {
    override fun getDescription(): String {
        return "${super.getDescription()}, with milk"
    }

    override fun getCost(): Double {
        return super.getCost() + 0.5
    }
}

class SugarDecorator(private val coffee: Coffee) : CoffeeDecorator(coffee) {
    override fun getDescription(): String {
        return "${super.getDescription()}, with sugar"
    }

    override fun getCost(): Double {
        return super.getCost() + 0.2
    }
}

使用时:

fun main() {
    var coffee = SimpleCoffee()
    println("${coffee.getDescription()}: $${coffee.getCost()}")

    coffee = MilkDecorator(coffee)
    println("${coffee.getDescription()}: $${coffee.getCost()}")

    coffee = SugarDecorator(coffee)
    println("${coffee.getDescription()}: $${coffee.getCost()}")
}

在这个例子中,Coffee 接口定义了获取描述和价格的方法。SimpleCoffee 是具体的咖啡实现。CoffeeDecorator 是抽象的装饰器,它继承自 Coffee 并持有一个 Coffee 对象。MilkDecoratorSugarDecorator 是具体的装饰器,它们在原有咖啡的基础上添加了新的功能。

六、代理模式

6.1 概念

代理模式为其他对象提供一种代理以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用。

6.2 实现

interface Image {
    fun display()
}

class RealImage(private val filename: String) : Image {
    init {
        loadFromDisk(filename)
    }

    private fun loadFromDisk(filename: String) {
        println("Loading $filename from disk")
    }

    override fun display() {
        println("Displaying $filename")
    }
}

class ProxyImage(private val filename: String) : Image {
    private var realImage: RealImage? = null

    override fun display() {
        if (realImage == null) {
            realImage = RealImage(filename)
        }
        realImage?.display()
    }
}

使用时:

fun main() {
    val proxyImage = ProxyImage("example.jpg")
    proxyImage.display()
    proxyImage.display()
}

在这个例子中,Image 接口定义了显示图像的方法。RealImage 是实际的图像对象,它在初始化时会从磁盘加载图像。ProxyImage 是代理对象,它在需要显示图像时才创建 RealImage 对象,从而实现延迟加载,减少资源消耗。

七、适配器模式

7.1 概念

适配器模式将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

7.2 类适配器实现

class Adaptee {
    fun specificRequest() {
        println("Adaptee's specific request")
    }
}

interface Target {
    fun request()
}

class ClassAdapter : Adaptee(), Target {
    override fun request() {
        specificRequest()
    }
}

使用时:

fun main() {
    val adapter = ClassAdapter()
    adapter.request()
}

在类适配器中,ClassAdapter 继承自 Adaptee 并实现 Target 接口,通过这种方式将 Adaptee 的接口适配成 Target 的接口。

7.3 对象适配器实现

class Adaptee {
    fun specificRequest() {
        println("Adaptee's specific request")
    }
}

interface Target {
    fun request()
}

class ObjectAdapter(private val adaptee: Adaptee) : Target {
    override fun request() {
        adaptee.specificRequest()
    }
}

使用时:

fun main() {
    val adaptee = Adaptee()
    val adapter = ObjectAdapter(adaptee)
    adapter.request()
}

在对象适配器中,ObjectAdapter 持有 Adaptee 的实例,并在 request 方法中调用 AdapteespecificRequest 方法,从而实现接口的适配。对象适配器相比类适配器更加灵活,因为它可以通过组合不同的 Adaptee 实例来实现不同的适配功能。

八、模板方法模式

8.1 概念

模板方法模式定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

8.2 实现

abstract class AbstractGame {
    fun play() {
        initialize()
        startPlay()
        endPlay()
    }

    protected abstract fun initialize()
    protected abstract fun startPlay()
    protected abstract fun endPlay()
}

class Cricket : AbstractGame() {
    override fun initialize() {
        println("Cricket game initialized. Start playing.")
    }

    override fun startPlay() {
        println("Cricket game started. Enjoy the game!")
    }

    override fun endPlay() {
        println("Cricket game finished.")
    }
}

class Football : AbstractGame() {
    override fun initialize() {
        println("Football game initialized. Start playing.")
    }

    override fun startPlay() {
        println("Football game started. Enjoy the game!")
    }

    override fun endPlay() {
        println("Football game finished.")
    }
}

使用时:

fun main() {
    val cricket = Cricket()
    cricket.play()

    val football = Football()
    football.play()
}

在这个例子中,AbstractGame 定义了游戏的模板方法 play,其中包含了游戏的基本流程,而具体的初始化、开始和结束步骤由子类 CricketFootball 来实现。通过这种方式,不同的游戏可以复用相同的算法骨架,同时又能根据自身特点实现特定的步骤。

九、责任链模式

9.1 概念

责任链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处理它为止。

9.2 实现

abstract class Handler {
    protected var nextHandler: Handler? = null

    fun setNext(handler: Handler): Handler {
        nextHandler = handler
        return handler
    }

    abstract fun handleRequest(request: Int)
}

class ConcreteHandler1 : Handler() {
    override fun handleRequest(request: Int) {
        if (request in 0..10) {
            println("ConcreteHandler1 handled request $request")
        } else {
            nextHandler?.handleRequest(request)
        }
    }
}

class ConcreteHandler2 : Handler() {
    override fun handleRequest(request: Int) {
        if (request in 11..20) {
            println("ConcreteHandler2 handled request $request")
        } else {
            nextHandler?.handleRequest(request)
        }
    }
}

class ConcreteHandler3 : Handler() {
    override fun handleRequest(request: Int) {
        if (request in 21..30) {
            println("ConcreteHandler3 handled request $request")
        } else {
            nextHandler?.handleRequest(request)
        }
    }
}

使用时:

fun main() {
    val handler1 = ConcreteHandler1()
    val handler2 = ConcreteHandler2()
    val handler3 = ConcreteHandler3()

    handler1.setNext(handler2).setNext(handler3)

    handler1.handleRequest(5)
    handler1.handleRequest(15)
    handler1.handleRequest(25)
    handler1.handleRequest(35)
}

在这个例子中,Handler 是抽象类,定义了设置下一个处理者和处理请求的方法。ConcreteHandler1ConcreteHandler2ConcreteHandler3 是具体的处理者,它们根据请求的范围来决定是否处理请求,如果不能处理则传递给下一个处理者。

十、状态模式

10.1 概念

状态模式允许一个对象在其内部状态改变时改变它的行为,对象看起来似乎修改了它的类。

10.2 实现

interface OrderState {
    fun processOrder(order: Order)
}

class NewOrderState : OrderState {
    override fun processOrder(order: Order) {
        println("Processing new order")
        order.setState(InProgressOrderState())
    }
}

class InProgressOrderState : OrderState {
    override fun processOrder(order: Order) {
        println("Order is in progress")
        order.setState(CompletedOrderState())
    }
}

class CompletedOrderState : OrderState {
    override fun processOrder(order: Order) {
        println("Order is completed")
    }
}

class Order {
    private var state: OrderState = NewOrderState()

    fun setState(state: OrderState) {
        this.state = state
    }

    fun process() {
        state.processOrder(this)
    }
}

使用时:

fun main() {
    val order = Order()
    order.process()
    order.process()
    order.process()
}

在这个例子中,OrderState 接口定义了处理订单的方法,NewOrderStateInProgressOrderStateCompletedOrderState 是具体的订单状态实现。Order 类持有一个 OrderState 对象,并通过 process 方法委托给当前状态对象来处理订单,随着订单处理的进行,状态会发生改变,从而表现出不同的行为。

通过以上对 Kotlin 中各种设计模式的介绍和实现,开发者可以更好地利用设计模式来优化代码结构,提高代码的可维护性、可扩展性和复用性,使 Kotlin 项目更加健壮和高效。在实际开发中,应根据具体的需求和场景选择合适的设计模式,以达到最佳的开发效果。同时,随着项目的不断发展和演变,可能需要对设计模式进行适当的调整和组合,以适应新的业务需求。