美文网首页程序员架构算法设计模式和编程理论公众号【麦小丁】征集优质文章
甲方不断改需求?如何以不变应万变——设计模式之桥接模式

甲方不断改需求?如何以不变应万变——设计模式之桥接模式

作者: 溪石iOS | 来源:发表于2018-12-11 21:34 被阅读11次

徒弟小M接到任务开发一个画图程序,其中一个功能是画多边形:预置“矩形”和“三角形”。
他已经学习过面向对象的开发方式,于是设计类如下:


设计模式-桥接模式.001

刚开始他决定用Quart2D绘制,


设计模式-桥接模式.002

开发过程中,他发现,用贝塞尔曲线也可以绘制多边形,但不知道哪种方法更好,于是他决定保留已经开发好的Quart2D绘制方法,再用UIBezierPath实现,这样方便对比哪种效果好。


设计模式-桥接模式.003

完成矩形和三角形后,甲方要求添加一个“五边形”,这时小M发现,他必须为“五边形”分别也写两套方法:
三种图形共需要6套绘制代码。

如果他继续研究,发现还可以用CAShapeLayer来绘制图形,这时绘制代码将达到3x3=9套, 设计模式-桥接模式.004

他为什么会陷入这种指数级增长的代码中呢?原因是形状类在变化,绘制方法也在变化,两种变化在继承模式下,处于紧耦合关系。
对于这种对象在“两个维度上”变化的情况,GOF“四人组”提出了“桥接模式”
下面我们通过实际重构说明这种模式的实现过程:
首先,我们先将绘图抽象出来:

@interface DrawImp : NSObject
- (void)drawLinesWithPoints:(CGPoint *)points count:(int)count;
@end

将不同的绘图方式,放到不同的DrawImp子类中:
实际画线1(Quartz方式):

@interface QuartzDrawImp : DrawImp

@end

@implementation QuartzDrawImp
- (void)drawLinesWithPoints:(CGPoint *)points count:(int)count {
    //Quartz
    CGContextRef context = UIGraphicsGetCurrentContext();
    
    UIColor *aColor = [UIColor colorWithRed:0 green:1.0 blue:0 alpha:0];
    CGContextSetRGBStrokeColor(context, 1.0, 0, 0, 1.0);
    CGContextSetFillColorWithColor(context, aColor.CGColor);
    CGContextSetLineWidth(context, 2.0);
    CGContextAddLines(context, points, count);
    CGContextDrawPath(context, kCGPathStroke);
}
@end

实际画线2(贝塞尔曲线方式):

@interface BezierDrawImp : DrawImp

@end
@implementation BezierDrawImp
- (void)drawLinesWithPoints:(CGPoint *)points count:(int)count {
    UIColor *color = [UIColor orangeColor];
    [color set];
    //创建path
    UIBezierPath *path = [UIBezierPath bezierPath];
    //设置线宽
    path.lineWidth = 3;
    //线条拐角
    path.lineCapStyle = kCGLineCapRound;
    //终点处理
    path.lineJoinStyle = kCGLineJoinRound;
    
    [path moveToPoint:points[0]];
    for (int i = 1; i < count; i++) {
        [path addLineToPoint:points[i]];
    }
    [path closePath];
    //根据坐标点连线
    [path stroke];
}
@end

对形状类进行重构,将绘制操作提到Shape类中:

@interface Shape : UIView
@property(nonatomic, strong) DrawImp *drawImp;

- (void)drawLinesWithPoints:(CGPoint *)points count:(int)count;
@end

@implementation Shape
- (void)drawLinesWithPoints:(CGPoint *)points count:(int)count {
    if (self.drawImp) {
        [self.drawImp drawLinesWithPoints:points count:count];
    }
}
@end

这时你会发现,形状绘制变得非常精简:

@implementation Triangle
- (void)drawRect:(CGRect)rect {
    CGPoint aPoints[4];
    aPoints[0] =CGPointMake(40, 10);
    aPoints[1] =CGPointMake(70, 60);
    aPoints[2] =CGPointMake(10, 60);
    aPoints[3] =CGPointMake(40, 10);
    [self drawLinesWithPoints:aPoints count:4];
}
@end

代码干净地好像“多种绘制方法”不存在一样!(矩形的绘制雷同,略去)

我们来看下“桥接模式”下的类关系图:


设计模式-桥接模式.005

桥在哪里?

"桥"在抽象层,在定义类和实现类之间,通过类关联(区别与继承)形成了一座桥:


设计模式-桥接模式.006

通过这座桥,定义和实现之间既联系,又分离,既可协同工作,又可独自扩展,添加新的图形和新的绘图方法都变得轻而易举。

调用者的位置

最后,我们来看下调用者的代码:

Triangle *triangle = [[Triangle alloc] initWithFrame:CGRectMake(80.0, 80.0, 100.0, 100.0)];
triangle.drawImp = [[QuartzDrawImp alloc] init];
[self.view addSubview:triangle];
    
Square *square = [[Square alloc] initWithFrame:CGRectMake(180.0, 80.0, 100.0, 100.0)];
square.drawImp = [[BezierDrawImp alloc] init];
[self.view addSubview:square];

从代码看出,调用者可以灵活的指定绘制方法,而无需修改任何形状类相关代码,形状类和绘制类被彻底解耦!

思考题

桥接模式体现了OOP面向对象设计的哪些原则呢?期待你的留言。

相关文章

  • 甲方不断改需求?如何以不变应万变——设计模式之桥接模式

    徒弟小M接到任务开发一个画图程序,其中一个功能是画多边形:预置“矩形”和“三角形”。他已经学习过面向对象的开发方式...

  • 设计模式之桥接模式

    设计模式之桥接模式 1. 模式定义 桥接模式又称柄体模式或接口模式,它是一种结构性模式。桥接模式将抽象部分与实现部...

  • Java设计模式——桥接模式

    Java设计模式之桥接模式 回顾 上一期分享了适配器模式,主要为了实现解耦 桥接模式 简介 桥接模式是对象的结构模...

  • 设计模式-桥接模式

    设计模式-桥接模式 定义 桥接模式(Bridge Pattern)也称为桥梁模式、接口(Interface)模式或...

  • 桥接模式

    设计模式:桥接模式(Bridge)

  • 设计模式之桥接模式

    设计模式之桥接模式 Intro 桥接模式(Bridge),将抽象部分与它的实现部分分离,使得它们都可以独立地变化。...

  • 设计模式——桥接模式

    设计模式——桥接模式 最近公司组件分享设计模式,然而分配给我的是桥接模式。就在这里记录我对桥接模式的理解吧。 定义...

  • 设计模式之桥接模式

    桥接模式(Bridge),将抽象部分与它的实现部分分离,使它们都可以独立地变化。优先使用对象的合成/聚合将有助于你...

  • 设计模式之桥接模式

    桥接模式:将抽象部分与他实现部分分离,使它们可以独立。 UML图: 使用场景:1、如果一个系统需要在构件的抽象化角...

  • 设计模式之桥接模式

    桥接模式 人的抽象类,这类人喜欢投资 美国人的投资方式 毁天灭地的中国大妈类,所到之处寸草不生 资产接口 , 具有...

网友评论

    本文标题:甲方不断改需求?如何以不变应万变——设计模式之桥接模式

    本文链接:https://www.haomeiwen.com/subject/jubzcqtx.html