要了解多型,先來看抽象、封裝、繼承吧
structure
在白話說一點,用一致的介面做不同的功能,舉個例子
燃油車和電動車,他們引擎的運作方式不同,在駕駛操作方向盤時概念還是一樣的,並不需要去學電動車的操作方式,甚至是每款汽車型號,其內部架構也會有些許出入,但我們只會學一次方向盤、燈號、雨刷外部介面的操作方式,就可以套用在所有通用車上
而其目的在於消除類別之間的耦合,使其更容易維護
一個多型類別依賴圖的範例
我們假設你有一段程式要執行駕駛 Mini 的行為,所以你寫了這個類別
class Mini{
fun drive(){
startEngine()
}
private fun startEngine() {
println("mini")
}
}
fun drive(transportation:Mini){
transportation.drive()
}
你說這不好嗎?他能執行,能跑的代碼就是好代碼
其實真沒有很好,一個依賴 mini
的韓式,就只有 mini
能使用,今天新需求來了,功能還要可以駕駛 LandRover
,難道要有 driveMini
和driveLandRover
兩種函式嗎?
既然 LandRover 和 Mini 都有共同的抽象概念,我們來為此抽取出一些東西
interface Car {
fun drive()
fun startEngine
}
class Mini:Car {
override fun drive(){
}
override fun startEngine(){
}
}
class LandRover:Car {
override fun drive(){
}
override fun startEngine(){
}
}
fun drive(car:Car) {
car.drive()
}
到目前為止,已經有不錯的抽象了,我們不管哪種車型,都可以透過 car
的接口操作,但我們仍面對兩個難題
我們最終的程式碼會長這樣,透過DriverInterface
抽象定義了駕駛行為的接口,在abstract class Car
裡面,封裝了startEngine
方法,並將其在各類別汽車中實現,另一方面,Carriage
也以相同方式封裝,而把 getHorse
隱藏,而對外的公開以 DriveInterface
為主,所有實現了該介面接口的類型,都可以被調用,而不必在意內部實作
fun main() {
drive(Mini())
drive(WeddingCarriage())
}
fun drive(transportation:DriverInterface){
transportation.drive()
}
abstract class Carriage:DriverInterface {
override fun drive() {
getHorse()
}
protected abstract fun getHorse()
}
class WeddingCarriage:Carriage() {
override fun getHorse() {
println("happy")
}
}
abstract class Car:DriverInterface{
override fun drive() {
startEngine()
}
protected abstract fun startEngine()
}
class LandRover:Car() {
override fun startEngine() {
TODO("Not yet implemented")
}
}
class Mini:Car(){
override fun startEngine() {
println("mini")
}
}
interface DriverInterface {
fun drive()
}
多型搭配繼承、抽象、資訊隱藏,可以讓我們在很低的依賴關係下為個類別完成不同的邏輯,運用得好,程式能有良好的內聚、低耦合、好維護等特徵
要了解多型,先來看抽象、封裝、繼承吧
In order to understand polymorphism, check out abstract, encapsulation and inheritance
structure
To describe polymorphism in one sentence is using same interface to wrap detail
, for example, fuel car and electric car, the engine works differently, but the operation on steering wheel is same, you don't have to learn how to drive electric car, even every car might have different architecture, but the user interface is fit is common.
The polymorphism can decouple classes, make the system maintainable
Demo class dependency graph on polymorphism
Since you want to execute the behavior to drive Mini, you here comes the class
class Mini{
fun drive(){
startEngine()
}
private fun startEngine() {
println("mini")
}
}
fun drive(transportation:Mini){
transportation.drive()
}
Does it good design?A running program is good program
Actually not, the function relay on mini
, therefore only mini
can use it, what if you need the function works on LandRover
, don't write duplicate code for driveMini
and driveLandRover
Since LandRover
and Mini
has same abstract concept, let's subtract something
interface Car {
fun drive()
fun startEngine
}
class Mini:Car {
override fun drive(){
}
override fun startEngine(){
}
}
class LandRover:Car {
override fun drive(){
}
override fun startEngine(){
}
}
fun drive(car:Car) {
car.drive()
}
So far, we have a good abstract, whatever model of car can fit the interface of car
, but we still facing two issue
startengine
and drive
, there is issue on operator orderIn the end our code will look like this, by usingDriverInterface
define interface of drive behavior, inside of abstract class Car
encapsulate startEngine
method, and implement in each instance of car, on the other side, Carriage
encapsulate in same way, hiding getHorse
, we exposed DriveInterface
, so all the function relay on DriveInterface
can handle all kind of vehicle
fun main() {
drive(Mini())
drive(WeddingCarriage())
}
fun drive(transportation:DriverInterface){
transportation.drive()
}
abstract class Carriage:DriverInterface {
override fun drive() {
getHorse()
}
protected abstract fun getHorse()
}
class WeddingCarriage:Carriage() {
override fun getHorse() {
println("happy")
}
}
abstract class Car:DriverInterface{
override fun drive() {
startEngine()
}
protected abstract fun startEngine()
}
class LandRover:Car() {
override fun startEngine() {
TODO("Not yet implemented")
}
}
class Mini:Car(){
override fun startEngine() {
println("mini")
}
}
interface DriverInterface {
fun drive()
}
polymorphism works with inheritance, abstract, hiding information, so we can write decoupled design for different logic