The closer you look, the less you see.
Now you see me.
要描述抽象,難就難在他很抽象,在 Kotlin 裡面,程式碼面抽象有兩種作法 interface, abstract class
,透過抽象的定義,可以使調用方依賴於抽象而非實體,可以輕鬆的替換、降低耦合,而且也不再受限於依賴的建構子,只要實作類別能完成介面定義的公開方法就行,不是要重複使用才做抽象設計,即使有多個類別有屬於自己的抽象也沒問題,但也不要為做而做,變成過度設計了
抽象設計著重在
但一切先從簡單的開始看吧,interface
是最基本的一種程式抽象
像是電腦的鍵盤本身也是一種抽象,當我們打字時,會按下不同的字母,而螢幕上會出現我們按下的內容
interface Keyboard {
fun input()
}
interface Screen {
fun display()
}
這我們並不關心背後的原理,像是訊號傳遞、轉換、記憶體、電位變化等等,只透過介面操作,可以讓我們以最小的可見性達到需要的成果,不需知道必要以外的細節(解耦)
那換到真實的程式裡面呢?
interface UserRepository{
fun getUserProfile():UserProfile
}
class MockRepo:UserRepository{
override fun getUserProfile():UserProfile
}
class UserProfileImpl(
api:Api,
db:Room
):UserProfile {
override fun getUserProfile():UserProfile
}
class useCase(
userRepo:UserRepository
)
那反過來看,介面其實是一種接口,而為了被外部使用,介面不僅不實作方法,他所有的方法也都會是公開的
而abstarct class
和 interface
最大的差異在於, abstartct class
可以持有屬性、以定義的方法和尚未定義的方法,可以提供沒有實現,或是不完整的實現
class Telsa:Car(){
override fun main() {
println("hohoho")
}
}
abstract class Car {
private val str = "toast"
fun toast(){
println(str)
main()
}
abstract fun main()
}
Tesla().toast()
//toast
//hohoho
最大的一個特點在於,在抽象類別裡,可以定義方法去呼叫還沒被實現的方法
不論是 interface
或是 abstract class
都可以為程式達到解耦的效果
interface : 定義未實現的公開方法接口
abstract class : 可定義未實現的接口、商業邏輯(以實現的)、 private property
抽象可以讓我們得以控制依賴圖的方向,類別實體不應依賴於他們不直接使用的東西
今天來用釀紅酒學抽象吧
紅酒在大家的印象可能是好市多的酒櫃,一箱一箱的酒瓶,那紅酒瓶本身其實就是抽象
interface Wine{
fun aroma()
fun taste()
}
而實作的部分會交給 factory
,把紅葡萄除梗、榨汁、浸皮、過濾、控溫、發酵、品檢、熟成,最後做成紅酒
class WineFactory(
yeast:Yeast,
grape:Grape,
sugar:Sugar
):AbstarctWineFactory,WineSeller{
private fun pressGrapeJuice()
private fun ferment()
private fun aged()
override fun produceWine():Wine
}
然後紅酒可能會簡單的分成各產區我以前的品酒老師看到這還不把我殺了
class FranceWine:Wine{
override fun aroma()
override fun taste()
}
class ItalyWine:Wine {
override fun aroma()
override fun taste()
}
而每款酒的香味和口感,則各依照他們的實作而有所不同
It is hard to describe abstract, because itself is abstract, in Kotlin, there are two way to define abstract behaviorinterface, abstract class
, by using abstract, the caller could relay on abstract instead of instance, can easily replace instance, decouple, and no longer restrict on constructure, as long as the class can implement the abstract method, on the other hands, abstract is not only for reuse, you can define abstract for a class with a good reason.
abstratc focus on
Let's start from simple one, interface
is the basic of abstract in programming
like keyboard itself is an abstract, when we are typing, we press on different alphabet, and the screen display those content
interface Keyboard {
fun input()
}
interface Screen {
fun display()
}
We don't care about the theory under it, by using operator defined in interface we can rely on minimum visibility to get what we need , without knowing too much detail (decouple)
What is it like in programming?
interface UserRepository{
fun getUserProfile():UserProfile
}
class MockRepo:UserRepository{
override fun getUserProfile():UserProfile
}
class UserProfileImpl(
api:Api,
db:Room
):UserProfile {
override fun getUserProfile():UserProfile
}
class useCase(
userRepo:UserRepository
)
interface is build for used, so it won;t implement method itself, and its methods will be open
The difference betweenabstract class
and interface
is abstract class
can holding properties, define method and undefine method
class Telsa:Car(){
override fun main() {
println("hohoho")
}
}
abstract class Car {
private val str = "toast"
fun toast(){
println(str)
main()
}
abstract fun main()
}
Tesla().toast()
//toast
//hohoho
Inside abstract class, you can define method to call undefined method
Both interface
and abstract class
could decouple program
interface : provide undefined method
abstract class : provide undefined method、business(defined method)、 private property
Using abstract allow us to control direction of dependency graph, class instance shouldn't relay on things they won't use directorly