設計模式,重要嗎?
我擺在這麼後面的理由,就是因為他不是最重要的,甚至是說,寧願你把程式碼先寫好,也不用先去學設計模式
當你先去學設計模式,你可能會硬套進現有專案,變成有設計模式的糙 code,但相反的,如果你先把程式寫好,你就已經自然地學會了幾種設計模式了
那回到我們主題上,設計模式主要可以分成三類,建構、結構以及行為,礙於篇幅,我只能每個類型分享幾種常見的實作,以及注意事項,在同個平台上,我推薦的文章是 什麼?又是/不只是 Design Patterns!?
前情提要,我被讀者制止了一次講三類設計模式XD
structure
單例,這是最好入門、最方便、最常誤用也最多人愛分享的設計模式了,我相信每篇文章都有其優點,但大家記得多看多比較,去了解比較全面的知識呀
首先,單例模式是個 anti-pattern ,如果一篇文章只說單例的優點,別看了不值得,但相對的,你也絕對不是直接不學單例,單例有其優劣,請真正了解後,再決定是否使用他
我們先回到單例模式本身,這個設計模式有兩個特點
而 Kotlin 裡面,更是提供了最簡短的方式建立單例,語法如下
object SingleObj {
}
在 Kotlin 語法裡,還可以用可見度修飾符限制可見度,像是 private object SingleObj {}
阿,這就完了?要是只學到這邊,就別說你會單例模式了拜託
單例模式還需要注意幾個問題
現在我們先撇開語法糖,來看看幾種實現單例的方式
public class SingleObj {
private SingleObj(){}//私有構造函式
private static SingleObj instance = new SingleObj();//用其私有的靜態變數紀錄實例
public static SingleObj getInstance(){//對外公開外部訪問方法
return instance;
}
}
現在來看看下面這段
public final class SingleObj {
@NotNull
public static final SingleObj INSTANCE;//用其私有的靜態變數紀錄實例
private SingleObj() { //私有構造函式
}
static {
SingleObj var0 = new SingleObj();//對外公開外部訪問方法
INSTANCE = var0;
}
}
//其實就是 Kotlin
object SingleObj {
}
看完是不是覺得效果一樣呀,第一個是 Java 程式,第二的是 Kotlin object
反組譯的程式,沒錯,用 Object
做單例幫我們省下了那麼多代碼,這種實現方式當然也有其優劣
class SingleObj private constructor() {
companion object {
private var instance: SingleObj? = null
get() {
if (field == null) {
field = SingleObj()
}
return field
}
fun get(): SingleObj{
return instance!!
}
}
}
instance
,使兩邊的 if
條件都成立,而我們也能基於這個問題做改良,並產生新的問題class SingleObj private constructor() {
companion object {
private var instance: SingleObj? = null
get() {
if (field == null) {
field = SingleObj()
}
return field
}
@Synchronized
fun get(): SingleObj{
return instance!!
}
}
}
class SingleObj private constructor() {
companion object {
val instance: SingleObj by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
SingleObj() }
}
}
稍微一挖,就能找到這邊,這邊就三行程式是重點,4, 11, 16
Volatile
直譯是可揮發的,解決了可見性問題,加了這個關鍵字的變數,任何一個執行緒對他的修改,都會讓其他cpu快取記憶體的值過期,這樣就必須重新去記憶體拿最新的值,更細節看這
if (_v1 !== UNINITIALIZED_VALUE)
判斷是否已經有實例synchronized(lock)
保證函式或程式區塊執行時,同一時刻只能有一個方法到 critical section
,並保證共享變數的內存可見性
//LazyJVM.kt
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {//如果已經有實例了就回傳
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue// 記下實例
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
SingleObj.instance
時,才會執行s=SingleObj()
產生實體class SingleObj private constructor() {
companion object {
val instance = SingletonHolder.holder
}
private object SingletonHolder {
val holder= SingleObj()
}
}
enum
的單例以上,還只是單例的冰山一角,理解了作法,來了解下為什麼有人說單例是 anti pattern?
Global State 導致測試上的困難
但這個可能導致的事,不同引用對其造成時序上的改變,而導致測試時無法重現狀態,簡單說 A 類別改了東西, B,C,D 一起爆掉
這問題就去看 Mutability 是把雙面刃 Mutability is double edged sword
https://cloud.tencent.com/developer/article/1803321
https://iter01.com/78974.html
https://iter01.com/573847.html
Design pattern, does it matter?
I put this topic in the end of this series, because it is not the most important technical, I rather you write good code first, than learn bunch of design pattern
When you learn design pattern, you might use it improperly, come out with shit design pattern code, on the opposite, if you wrote code with good habit, you will learn design pattern like free
Well, back to the topic, there are three kind of design pattern, build, structure and behavior, I will introduce some of common implement and its detail, in itHome I recommand this series article 什麼?又是/不只是 Design Patterns!?
article structure
Singleton, the most entry-level, convenience and misused design pattern,
First, Singleton is an anti-pattern, if you read an article only tell you advantage of singleton, don't read it, on the contract, you should actually understand singleton the decide whatever to use it
Back to the singleton pattern, here is some detail of it
In Kotlin, we provide more brief syntax to build singleton
object SingleObj {
}
With Kotlin syntax, we can use visibility modifier to limited it private object SingleObj {}
does it finish? If that is all you know, please don't tell others you understand singleton
there are following question in singleton
Now let's take a look with Kotlin syntax sugar
public class SingleObj {
private SingleObj(){}//private constructor method
private static SingleObj instance = new SingleObj();// use private static variable record instance
public static SingleObj getInstance(){//publish access methods
return instance;
}
}
now check the code block
public final class SingleObj {
@NotNull
public static final SingleObj INSTANCE;//use private static variable record instance
private SingleObj() {//private constructor method
}
static {
SingleObj var0 = new SingleObj();///publish access methods
INSTANCE = var0;
}
}
//actually it is Kotlin
object SingleObj {
}
Do you feel it look the same, first one is Java code, the second one is decompiled Kotlin object
, indeed the object
keyword save us lots of boilerplate code, but what it the pros and cons
class SingleObj private constructor() {
companion object {
private var instance: SingleObj? = null
get() {
if (field == null) {
field = SingleObj()
}
return field
}
fun get(): SingleObj{
return instance!!
}
}
}
instance
, and if
condition in both thread also success, therefore we can make the implement betterclass SingleObj private constructor() {
companion object {
private var instance: SingleObj? = null
get() {
if (field == null) {
field = SingleObj()
}
return field
}
@Synchronized
fun get(): SingleObj{
return instance!!
}
}
}
class SingleObj private constructor() {
companion object {
val instance: SingleObj by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
SingleObj() }
}
}
if you dig deep, you will find those code scope, the ley line is 4, 11, 16
Volatile
fix the visibility issue, any variable with this keyword, whatever thread modify this variable, will expire the value in other cpu cache memory, so other thread have to get the newest value check out more detail
if (_v1 !== UNINITIALIZED_VALUE)
check does the instance existssynchronized(lock)
guarantee function or program only one client access critical section
in same time, and it also make sure the memory visibility
//LazyJVM.kt
private class SynchronizedLazyImpl<out T>(initializer: () -> T, lock: Any? = null) : Lazy<T>, Serializable {
private var initializer: (() -> T)? = initializer
@Volatile private var _value: Any? = UNINITIALIZED_VALUE
// final field is required to enable safe publication of constructed instance
private val lock = lock ?: this
override val value: T
get() {
val _v1 = _value
if (_v1 !== UNINITIALIZED_VALUE) {//if have instance, return
@Suppress("UNCHECKED_CAST")
return _v1 as T
}
return synchronized(lock) {
val _v2 = _value
if (_v2 !== UNINITIALIZED_VALUE) {
@Suppress("UNCHECKED_CAST") (_v2 as T)
} else {
val typedValue = initializer!!()
_value = typedValue// record the instance
initializer = null
typedValue
}
}
}
override fun isInitialized(): Boolean = _value !== UNINITIALIZED_VALUE
override fun toString(): String = if (isInitialized()) value.toString() else "Lazy value not initialized yet."
private fun writeReplace(): Any = InitializedLazyImpl(value)
}
Static inner class only construct while other program call it, in the other words, only initialize when execute SingleObj,instance
it will run s=SingleObj()
class SingleObj private constructor() {
companion object {
val instance = SingletonHolder.holder
}
private object SingletonHolder {
val holder= SingleObj()
}
}
enum
https://cloud.tencent.com/developer/article/1803321
https://iter01.com/78974.html
https://iter01.com/573847.html