【設(shè)計模式】通過在蘋果官網(wǎng)購買iPhone配件了解裝飾器模式
背景
一個iPhone,可以套上保護(hù)殼(ConcDecorator A),也可以再套上無線充(ConcDecorator B),得到最后的效果(execute)。
蘋果無需發(fā)布新的型號(繼承),我們簡單地通過裝飾(組合)就可以得到想要的最終產(chǎn)品。
模式定義
Attach additional responsibilities to an object dynamically keeping the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
為動態(tài)保持相同接口的對象附加額外的職責(zé)。裝飾器為擴(kuò)展功能提供了一種靈活的選擇,而不是子類化。
可以看到,是十分符合我們的需求的,每一個裝飾品如保護(hù)殼、無線充,就是一個個可以嵌套的裝飾器。
https://refactoringguru.cn/design-patterns/decorator
模式實現(xiàn)
1.定義iPhone接口
主要定義了iPhone模板的說明接口方法getDesc,后續(xù)以這個方法為核心,展開嵌套。
package com.example.designpattern.decorator;
/**
* 手機(jī)
*
* @author hongcunlin
*/
public interface Phone {
/**
* 介紹
*
* @return 介紹內(nèi)容
*/
String getDesc();
}
2.實現(xiàn)iPhone接口
簡單試下getDesc的方法,目前是一個裸機(jī)的iPhone。
package com.example.designpattern.decorator.impl;
import com.example.designpattern.decorator.Phone;
/**
* 蘋果手機(jī)iPhone 14 Pro Max
*
* @author hongcunlin
*/
public class Iphone implements Phone {
@Override
public String getDesc() {
return "iPhone";
}
}
3.定義iPhone裝飾器抽象類
裝飾器的超類,里邊存放iPhone屬性,圍繞它進(jìn)行嵌套。
package com.example.designpattern.decorator.impl.decorator;
import com.example.designpattern.decorator.Phone;
/**
* 手機(jī)裝飾器
*
* @author hongcunlin
*/
public abstract class IphoneDecorator implements Phone {
/**
* 手機(jī)(抽象類存在的意義,否則就使用接口了)
*/
protected Phone phone;
/**
* 構(gòu)造方法
*
* @param phone 手機(jī)
*/
IphoneDecorator(Phone phone) {
this.phone = phone;
}
}
4.1.實現(xiàn)iPhone裝飾器之保護(hù)殼
嵌套一
package com.example.designpattern.decorator.impl.decorator;
import com.example.designpattern.decorator.Phone;
/**
* iPhone保護(hù)殼
*
* @author hongcunlin
*/
public class IphoneCaseDecorator extends IphoneDecorator {
/**
* 構(gòu)造方法
*
* @param phone 手機(jī)
*/
public IphoneCaseDecorator(Phone phone) {
super(phone);
}
@Override
public String getDesc() {
return "帶保護(hù)殼的" + phone.getDesc();
}
}
4.2.實現(xiàn)iPhone裝飾器之無線充
嵌套二
package com.example.designpattern.decorator.impl.decorator;
import com.example.designpattern.decorator.Phone;
/**
* iPhone無線充
*
* @author hongcunlin
*/
public class IphoneChargerDecorator extends IphoneDecorator {
/**
* 構(gòu)造方法
*
* @param phone 手機(jī)
*/
public IphoneChargerDecorator(Phone phone) {
super(phone);
}
@Override
public String getDesc() {
return "帶無線充的" + phone.getDesc();
}
}
5.測試
這里我們先初始化一個iPhone,接著帶上保護(hù)殼看看效果,最后再帶上無線充看看效果。
package com.example.designpattern.decorator;
import com.example.designpattern.decorator.impl.Iphone;
import com.example.designpattern.decorator.impl.decorator.IphoneCaseDecorator;
import com.example.designpattern.decorator.impl.decorator.IphoneChargerDecorator;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
@SpringBootTest
public class DesignPatternTest {
@Test
public void test() {
// 常規(guī)iPhone
Phone iphone = new Iphone();
System.out.println(iphone.getDesc());
// 帶保護(hù)殼的iPhone
iphone = new IphoneCaseDecorator(iphone);
System.out.println(iphone.getDesc());
// 帶無線充的帶保護(hù)殼的iPhone
iphone = new IphoneChargerDecorator(iphone);
System.out.println(iphone.getDesc());
}
}
可以看到,隨著裝飾器的層層嵌套,iPhone的模樣越來越復(fù)雜,是符合我們的預(yù)期的。
最后
裝飾器主要是通過組合的模式,對類內(nèi)容進(jìn)行擴(kuò)展,而不是通過繼承的方式,特別是在Java只能單繼承的情況,行之有效。
后面有空接著閑聊23種設(shè)計模式中的其他種。