實現一個同樣功能可以有各種方法,功能簡單時需要考慮的只有效率和可讀性,功能複雜時就需要額外考慮擴展性。在設計程序時,使用合適的設計模式,不僅可以解決擴展性問題,還可以讓程序結構更符合人類的思維直覺,富有藝術感。
這裏介紹了裝飾器模式。
裝飾器模式的說明是:動態地將責任(或功能)附加到對象上,若要擴展功能,裝飾者提供了比繼承更有彈性的替代方案。
Attach additional responsibilities to an object dynamically keeping the same interface.Decorators provide a flexible alternative to subclassing for extending functionality.
Talk is cheap, show me code
以 HTML 的渲染爲例,對一段文本 “hello world” 進行渲染,例如加黑、加斜體。
- Python 的裝飾器
# 加黑裝飾器
def renderbold(func):
def wrapped():
return "<b>" + func() + "</b>"
return wrapped
# 加斜體裝飾器
def renderitalic(func):
def wrapped():
return "<i>" + func() + "</i>"
return wrapped
# 自下而上調用裝飾器
@renderbold
@renderitalic
def helloworld():
return "hello world"
print(helloworld())
## 返回 <b><i>hello world</i></b>
- Java 實現裝飾器
/* 基礎抽象類 */
abstract class HtmlRender{
// 抽象地方法
public abstract String render();
}
/* 實體類,提供文本 */
class HelloWorldHtml extends HtmlRender{
@Override
public String render(){
return "hello world";
}
}
/* 裝飾器抽象類,和實體類一樣,繼承了基礎抽象類:裝飾之後的對象的基礎類型不變,只是多了一些責任 */
abstract class HtmlDecorator extends HtmlRender{
private HtmlRender htmlrender = null;
public HtmlDecorator(HtmlRender htmlrender){
this.htmlrender = htmlrender;
}
@Override
public String render(){
return this.htmlrender.render();
}
}
/* 裝飾器實體類,加黑裝飾器 */
class BoldDecorator extends HtmlDecorator{
public BoldDecorator(HtmlRender htmlrender){
super(htmlrender);
}
// 重寫父類的方法
public String render(){
String str = super.render();
return("<b>" + str + "</b>");
}
}
/* 裝飾器實體類,加斜體飾器 */
class ItalicDecorator extends HtmlDecorator{
public ItalicDecorator(HtmlRender htmlrender){
super(htmlrender);
}
// 重寫父類的方法
public String render(){
String str = super.render();
return("<i>" + str + "</i>");
}
}
class DecoratorDemo{
public static void main(String[] args){
HtmlRender htmlrender = new HelloWorldHtml();
// 第一次修飾,加斜體
htmlrender = new ItalicDecorator(htmlrender);
// 第二次修飾,加黑
htmlrender = new BoldDecorator(htmlrender);
// 渲染完畢
System.out.println(htmlrender.render());
}
}
// 輸出結果 <b><i>hello world</i></b>
總結
- Python 的裝飾器是語法的一部分,由於函數也是對象,可以直接裝飾函數,使用更直觀(像一個真實的裝飾品),但是定義裝飾器函數語法不太直觀,使用了閉包函數;
- Java 的裝飾器是一種面向對象的設計模式,使用了普通語法實現稍微複雜,且使用起來並且不太直觀;
- 一些簡單基本的功能不建議使用裝飾器,會影響可讀性。
參考資料
https://www.cnblogs.com/volcano-liu/p/10897897.html
https://www.jianshu.com/p/ab702e4d4ba7