定義
我覺得裝飾者模式是在已有功能的基礎之上,動態地添加更多 功能的一種方式,這些新加的代碼裝飾了原有類的 核心職責或主要行為。
裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是作為現有的類的一個包裝。
這種模式創建了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。
實例
之前的項目中開發一款石油行業繪圖軟件,其中有圖道和曲線繪製功能。基於同一組數據繪製的曲線略有不同。可以是線狀圖,也能是階梯圖裝、桿狀圖,曲線還需要填充功能,可以左側填充,右側填充、及間填充等。填充的內容也有很多類,比如:石灰岩、白雲岩、油氣水等等。
如下圖:
正好使用裝飾者模式,在繪製曲線的同時,在不影響曲線繪製的前提下,根據用戶需求動態增加各種額外的繪製功能。
廢話不多說,上類圖:
使用時候的代碼:
private ICurveDrawer GetCurveDrawerInstance()
{
ICurveDrawer loDrawer = null;
var curveDrawer = new CurveDrawer(this);
//曲線
switch (CurveStyle)
{
case ECurveStyle.Line:
loDrawer = curveDrawer;
switch (Overflow)
{
case EOverflowDrawType.Move://曲線移峰
loDrawer = new CurveMoveDrawer(this);
break;
case EOverflowDrawType.Mirror://曲線折峰
loDrawer = new CurveMirrorDrawer(this);
break;
}
break;
case ECurveStyle.Ladder:
loDrawer = new LadderCurveDrawer(this);
break;
case ECurveStyle.StickPlot:
loDrawer = new StickPlotCurveDrawer(this);
break;
case ECurveStyle.Point:
loDrawer = new PointCurveDrawer(this);
break;
case ECurveStyle.PointLine:
loDrawer = new PointCurveDrawer(this, curveDrawer);
break;
case ECurveStyle.StickPlotLine:
loDrawer = new StickPlotCurveDrawer(this, curveDrawer);
break;
case ECurveStyle.LeftFill:
loDrawer = new LeftFillCurveDrawer(this, curveDrawer);
break;
case ECurveStyle.RightFill:
loDrawer = new RightFillCurveDrawer(this, curveDrawer);
break;
case ECurveStyle.ClipFill:
loDrawer = new CurveFillCurveDrawer(this, curveDrawer);
break;
}
return loDrawer;
}
根據用戶的選擇不同,為用戶添加不同的裝飾者,進行曲線繪製。
總結一下該模式的使用:
當系統需要新功能的時候,要向舊的類中添加新的代碼,這些新加的代碼通常裝飾了原有類的核心職責或主要行為,這樣會導致一些問題:主類中由於加了新的字段,新的方法以及新的邏輯,從而增加了主類的複雜度。
裝飾模式提供了一個非常好的解決方案,它把每個要裝飾的功能放在單獨的類中,並讓這個類包裝它所要裝飾的對象,因此,當需要執行特殊行為的時候,客戶代碼就可以在運行的時候根據需要有選擇的、按順序的使用裝飾功能包裝對象。
好處:能有有效的把類的核心職責和裝飾功能區分開,而且可以去除相關類中重複的裝飾邏輯,把類中的裝飾功能從類中搬除,可以簡化原來的類。
附代碼:
///
/// 曲線繪製裝飾者
///
public class CurveDrawerDecorator : CurveDrawerBase
{
private readonly ICurveDrawer _drawer;
protected CurveDrawerDecorator(Curve curve)
: base(curve)
{
}
protected CurveDrawerDecorator(Curve curve,ICurveDrawer drawer)
:base(curve)
{
this._drawer = drawer;
}
public override void Draw(Graphics g, PointF[] points, Pen pen, Brush brush)
{
if (_drawer != null)
{
var drawPoints = GetPointsInScrollBounds(points);
_drawer.Draw(g, drawPoints, pen, brush);
}
}
public override void DrawAlarm(Graphics g, PointF[] points, Pen pen, Brush brush)
{
if (_drawer != null)
{
var drawPoints = GetPointsInScrollBounds(points);
_drawer.DrawAlarm(g, drawPoints, pen, brush);
}
}
}
///
/// 曲線間填充
///
public class CurveFillCurveDrawer : CurveDrawerDecorator
{
public CurveFillCurveDrawer(Curve owner, ICurveDrawer drawer) :
base(owner, drawer)
{
}
public override void Draw(Graphics g, PointF[] points, Pen pen, Brush brush)
{
base.Draw(g, points, pen, brush);
var nextCurve = OwnerCurve.GetNextIndexCurve();
if (nextCurve == null || !nextCurve.Visible)
{
return;
}
var drawPoints = GetPointsInScrollBounds(points);
var rect = g.VisibleClipBounds;
rect.Intersect(OwnerCurve.Owner.Parent.CurShape.InnerRectangle);
var validPoints = OwnerCurve.GetVisiblePoints(drawPoints, rect, EFillType.Left);
using (var gp = new GraphicsPath())
{
gp.AddPolygon(validPoints.ToArray());
var nextValidPoints = OwnerCurve.GetVisiblePoints(GetPointsInScrollBounds(nextCurve.Points), rect, EFillType.Left);
using (var gpNext = new GraphicsPath())
{
gpNext.AddPolygon(nextValidPoints.ToArray());
var region = new Region(gp);
region.Xor(gpNext);
g.FillRegion(OwnerCurve.FillBrush, region);
region.Dispose();
gpNext.Dispose();
}
gp.Dispose();
}
}
}
閱讀更多 程序你好 的文章