结构型设计模式:装饰器(者)模式实例介绍

2018-07-23 09:44:55 浏览数 (2)

定义

我觉得装饰者模式是在已有功能的基础之上,动态地添加更多 功能的一种方式,这些新加的代码装饰了原有类的 核心职责或主要行为。

装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。

这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。

实例

之前的项目中开发一款石油行业绘图软件,其中有图道和曲线绘制功能。基于同一组数据绘制的曲线略有不同。可以是线状图,也能是阶梯图装、杆状图,曲线还需要填充功能,可以左侧填充,右侧填充、及间填充等。填充的内容也有很多类,比如:石灰岩、白云岩、油气水等等。

如下图:

正好使用装饰者模式,在绘制曲线的同时,在不影响曲线绘制的前提下,根据用户需求动态增加各种额外的绘制功能。

废话不多说,上类图:

使用时候的代码:

代码语言:javascript复制
 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;
        }

根据用户的选择不同,为用户添加不同的装饰者,进行曲线绘制。

总结一下该模式的使用:

当系统需要新功能的时候,要向旧的类中添加新的代码,这些新加的代码通常装饰了原有类的核心职责或主要行为,这样会导致一些问题:主类中由于加了新的字段,新的方法以及新的逻辑,从而增加了主类的复杂度。

装饰模式提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为的时候,客户代码就可以在运行的时候根据需要有选择的、按顺序的使用装饰功能包装对象。

好处:能有有效的把类的核心职责和装饰功能区分开,而且可以去除相关类中重复的装饰逻辑,把类中的装饰功能从类中搬除,可以简化原来的类。

附代码:

代码语言:java复制
/// <summary>
    /// 曲线绘制装饰者
    /// </summary>
    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);
            }
        }
    }
/// <summary>
    /// 曲线间填充
    /// </summary>
    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();
            }
        }
    }

0 人点赞