前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >结构型设计模式:装饰器(者)模式实例介绍

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

作者头像
程序你好
发布2018-07-23 09:44:55
3140
发布2018-07-23 09:44:55
举报
文章被收录于专栏:程序你好程序你好

定义

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

装饰器模式(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();
            }
        }
    }
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2018-06-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序你好 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 定义
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档