前语:

在软件开发中,规划形式是处理常见问题的可复用方案。装修器形式、署理形式和适配器形式是常用的结构型规划形式,它们在不同的场景中发挥着重要作用。本文将以幽默幽默的方式,详细解说这三个规划形式的原理、运用场景、优缺陷,并经过日子中的比如进行类比,协助读者更好地了解它们的差异和运用。

装修器形式

原理:

装修器形式经过动态地将新功用附加到目标上,完成在不改动其结构的状况下,对目标功用进行扩展。它运用一种包装目标的方式,将原始目标包装在一个或多个装修器目标中,并在运行时动态地增加新的行为。

运用场景:

装修器形式适用于以下场景:

  • 动态地为目标增加额定功用,而不需求修正原始目标的代码。
  • 在不影响其他目标的状况下,以不同的方式扩展目标的功用。
  • 需求按照特定次序组合多个功用的状况。

长处:

  • 具有灵活性:可以根据需求动态增加或删去功用。
  • 保持原始目标的接口和行为不变。
  • 可以完成多个装修器的组合,完成复杂的功用扩展。

缺陷:

  • 增加了类的数量,增加了代码复杂性。
  • 客户端需求了解装修器的作业原理,以正确运用。

示例:

假定咱们有一个简单的咖啡店,咱们可以经过装修器形式为咖啡增加额定的配料,如牛奶、糖浆或巧克力。下面是代码示例:

// 咖啡接口
interface Coffee {
    fun getCost(): Double
    fun getDescription(): String
}
// 原始咖啡类
class SimpleCoffee : Coffee {
    override fun getCost(): Double {
        return 1.0
    }
    override fun getDescription(): String {
        return "Simple Coffee"
    }
}
// 咖啡装修器类
abstract class CoffeeDecorator(private val coffee: Coffee) : Coffee {
    override fun getCost(): Double {
        return coffee.getCost()
    }
    override fun getDescription(): String {
        return coffee.getDescription()
    }
}
// 牛奶装修器
class MilkDecorator(coffee: Coffee) : CoffeeDecorator(coffee) {
    override fun getCost(): Double {
        return super.getCost() + 0.5
    }
    override fun getDescription(): String {
        return super.getDescription() + ", Milk"
    }
}
// 糖浆装修器
class SyrupDecorator(coffee: Coffee) : CoffeeDecorator(coffee) {
    override fun getCost(): Double {
        return super.getCost() + 0.3
    }
    override fun getDescription(): String {
        return super.getDescription() + ", Syrup"
    }
}
// 巧克力装修器
class ChocolateDecorator(coffee: Coffee) : CoffeeDecorator(coffee) {
    override fun getCost(): Double {
        return super.getCost() + 0.7
    }
    override fun getDescription(): String {
        return super.getDescription() + ", Chocolate"
    }
}
// 客户端代码
fun main() {
    val coffee: Coffee = SimpleCoffee()
    val decoratedCoffee: Coffee = MilkDecorator(SyrupDecorator(ChocolateDecorator(coffee)))
    println("Cost: ${decoratedCoffee.getCost()}")
    println("Description: ${decoratedCoffee.getDescription()}")
}

在上面的示例中,咱们界说了咖啡接口和原始咖啡类。然后,咱们创立了多个装修器类来扩展咖啡的功用,如牛奶装修器、糖浆装修器和巧克力装修器。经过将这些装修器目标层层包装在一同,咱们可以动态地为咖啡增加不同的配料,而不影响原始咖啡目标的接口和行为。

署理形式

原理:

署理形式为其他目标提供一种署理以操控对该目标的拜访。它经过在署理目标中创立一个与原始目标相同的接口,并在署理目标中操控对原始目标的拜访。

运用场景:

署理形式适用于以下场景:

  • 目标的拜访需求额定的操控,如权限操控、长途拜访等。
  • 在不改动原始目标的状况下,对其进行扩展或增强。
  • 目标的创立和毁掉需求额定的处理。

长处:

  • 可以在不改动原始目标的状况下,增强或操控对目标的拜访。
  • 可以完成长途署理、虚拟署理等不同类型的署理。

缺陷:

  • 增加了代码复杂性,引入了额定的直接层。

示例:

假定咱们有一个文件下载器,为了安全考虑,咱们期望在用户下载文件之前进行权限验证。下面是代码示例:

// 文件下载接口
interface FileDownloader {
    fun downloadFile(url: String)
}
// 文件下载器完成类
class SimpleFileDownloader : FileDownloader {
    override fun downloadFile(url: String) {
        println("Downloading file from $url")
    }
}
// 署理文件下载器
class ProxyFileDownloader(private val fileDownloader: FileDownloader) : FileDownloader {
    override fun downloadFile(url: String) {
        // 进行权限验证
        if (isUserAuthenticated()) {
            fileDownloader.downloadFile(url)
        } else {
            println("Access denied. Please login to download files.")
        }
    }
    private fun isUserAuthenticated(): Boolean {
        // 验证用户身份
        // 回来 true 或 false
        return false
    }
}
// 客户端代码
fun main() {
    val fileDownloader: FileDownloader = ProxyFileDownloader(SimpleFileDownloader())
    fileDownloader.downloadFile("https://example.com/file.txt")
}

在上面的示例中,咱们界说了文件下载接口和文件下载器完成类。然后,咱们创立了署理文件下载器类,它在下载文件之前进行权限验证。经过运用署理文件下载器,咱们可以操控对原始文件下载器的拜访,并在必要时进行额定的权限验证或其他处理。

适配器形式

原理:

适配器形式用于将一个类的接口转化成客户端所期望的另一个接口。它使得原本不兼容的类可以一同作业,经过适配器将客户端的恳求转化成对被适配目标的相应调用。

运用场景:

适配器形式适用于以下场景:

  • 需求将一个已存在的类集成到另一个类中。
  • 需求统一不同类的接口。

长处:

  • 可以使原本不兼容的类一同作业。
  • 可以在不修正已有代码的状况下进行接口的适配。

缺陷:

  • 增加了代码复杂性,引入了额定的适配器类。

示例:

假定咱们有一个音频播放器,它只能播放MP3格局的音乐。但是咱们现在有一些其他格局的音乐文件,如AAC、WAV等,咱们期望可以经过音频播放器播放这些文件。下面是代码示例:

// 音频播放器接口
interface AudioPlayer {
    fun playAudio(file: String)
}
// MP3播放器完成类
class Mp3Player : AudioPlayer {
    override fun playAudio(file: String) {
        println("Playing MP3 file: $file")
    }
}
// 音频适配器
class AudioAdapter(private val audioPlayer: AudioPlayer) : AudioPlayer {
    override fun playAudio(file: String) {
        // 将其他格局的音频文件转化成MP3格局
        val mp3File = convertToMp3(file)
        audioPlayer.playAudio(mp3File)
    }
    private fun convertToMp3(file: String): String {
        // 将其他格局的音频文件转化成MP3格局
        // 回来转化后的MP3文件途径
        return "converted_$file.mp3"
    }
}
// 客户端代码
fun main() {
    val audioPlayer: AudioPlayer = AudioAdapter(Mp3Player())
    audioPlayer.playAudio("song.aac")
}

在上面的示例中,咱们界说了音频播放器接口和MP3播放器完成类。然后,咱们创立了音频适配器类,它将其他格局的音频文件转化成MP3格局,并经过MP3播放器播放。经过运用适配器形式,咱们可以在不修正原始音频播放器的状况下,完成对其他格局音频文件的播放。

装修器形式 vs 署理形式 vs 适配器形式:差异与运用场景

装修器形式、署理形式和适配器形式都是结构型规划形式,它们在不同的场景中发挥作用,有着各自的特色和运用场景。

  • 装修器形式:首要用于动态地为目标增加额定的功用,而不修正原始目标的结构。适用于需求动态扩展目标功用的场景,如给咖啡增加配料。
  • 署理形式:首要用于操控对目标的拜访,可以在不改动原始目标的状况下增强或约束对目标的拜访。适用于需求操控目标拜访权限、增强目标功用或完成长途拜访的场景,如文件下载器中的权限验证。
  • 适配器形式:首要用于将一个类的接口转化成客户端所期望的另一个接口,使得原本不兼容的类可以一同作业。适用于需求统一不同类的接口或将已存在的类集成到另一个类中的场景,如音频播放器中将不同格局的音频文件转化成MP3格局。

尽管这三种形式在某些方面具有相似之处,但它们的目的和运用场景是不同的。了解它们的差异和适用场景可以协助咱们在开发过程中挑选合适的规划形式,以优化代码结构和功用扩展。

结语: 咱们详细介绍了装修器形式、署理形式和适配器形式。咱们评论了它们的原理、运用场景、优缺陷,并经过日子中的比如进行了类比。装修器形式用于动态扩展目标功用,署理形式用于操控目标拜访,适配器形式用于统一接口和类的适配。期望本文可以协助读者更好地了解和运用这些规划形式,提高软件开发的技术和效率。