結構型設計模式:裝飾器(者)模式實例介紹

結構型設計模式:裝飾器(者)模式實例介紹

定義

我覺得裝飾者模式是在已有功能的基礎之上,動態地添加更多 功能的一種方式,這些新加的代碼裝飾了原有類的 核心職責或主要行為。

裝飾器模式(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();

}

}

}


分享到:


相關文章: