方法封装的基本步骤

context

今天一同学问我封装时候的基本依据. 然后要详细一点 . 所以写了这篇文章.

封装的场景

  • 最舒服的方式应该是基于需求的封装 , 比如知道自己想怎么用了, 然后写出用法 , 编写方法的实现.
  • 可能是为了日后的拓展而进行的封装

对于第二种方式, 个人是不太建议的. 我们不应该去臆测将来的需求. 如果真的需要了, 通过重构去实现即可.

但是还是借着今天的机会, 说说我封装的时候的思考方式吧.

  1. 阅读方法, 明白方法的目的 ,例如以下的代码,一个关键帧动画.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
- (CAKeyframeAnimation *)createAnimation:(CGRect)frame {
CAKeyframeAnimation *animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef path = CGPathCreateMutable();

int height = -100 + arc4random() % 40 - 20;
int xOffset = frame.origin.x;
int yOffset = frame.origin.y;
int waveWidth = 50;
CGPoint p1 = CGPointMake(xOffset, height * 0 + yOffset);
CGPoint p2 = CGPointMake(xOffset, height * 1 + yOffset);
CGPoint p3 = CGPointMake(xOffset, height * 2 + yOffset);
CGPoint p4 = CGPointMake(xOffset, height * 2 + yOffset);

CGPathMoveToPoint(path, NULL, p1.x,p1.y);

if (arc4random() % 2) {
CGPathAddQuadCurveToPoint(path, NULL, p1.x - arc4random() % waveWidth, p1.y + height / 2.0, p2.x, p2.y);
CGPathAddQuadCurveToPoint(path, NULL, p2.x + arc4random() % waveWidth, p2.y + height / 2.0, p3.x, p3.y);
CGPathAddQuadCurveToPoint(path, NULL, p3.x - arc4random() % waveWidth, p3.y + height / 2.0, p4.x, p4.y);
} else {
CGPathAddQuadCurveToPoint(path, NULL, p1.x + arc4random() % waveWidth, p1.y + height / 2.0, p2.x, p2.y);
CGPathAddQuadCurveToPoint(path, NULL, p2.x - arc4random() % waveWidth, p2.y + height / 2.0, p3.x, p3.y);
CGPathAddQuadCurveToPoint(path, NULL, p3.x + arc4random() % waveWidth, p3.y + height / 2.0, p4.x, p4.y);
}
animation.path = path;
animation.calculationMode = kCAAnimationCubicPaced;
CGPathRelease(path);
return animation;
}
  1. 提取可能的变量 ,方法要灵活性, 那么就需要把需要变化的参数开放给方法使用者(以下简称开发者). 通常,方法中的局部变量都可以作为方法的参数.或者根据实际需要,添加其他参数.
1
int waveWidth = 50;

特别的, 能根据参数计算的局部变量,不应该作为参数,否则就冗余了.比如下面的两个

1
2
int xOffset = frame.origin.x;
int yOffset = frame.origin.y;

包含复杂计算过程的变量,也应该把计算过程封装到方法中.只暴露出索引,比如下面,我们将 -100抽出来,供使用者自定义,当然,可以根据需要把 40 和20 暴露

1
int height = -100 + arc4random() % 40 - 20;

所以,应该添加两个额外的参数(加上原来的frame,一共三个参数)

1
2
3
waveWidth
heightFactor
frame

方法的安排

  1. 类方法 or 实例方法

    • 看返回值的类型(CAKeyframeAnimation *)是否和容器(NSObject)有依赖关系(比如依赖属性) ,如果没有, 直接使用类方法,因为可以省去实例化类的步骤.
    • 如果有关系,可以采取先实例,然后封装到类方法的方式.
  1. 方法安排
    • 首先应该提供一个全参数方法,保证开发者能够更改所有值. 例如本例中,可以根据到现在的原则设计出一个这个方法:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
+ (CAKeyframeAnimation*)createAnimationWithFrame:(CGRect)frame waveWidth:(int)waveWidth heightFactor:(int)heightFactor
{
CAKeyframeAnimation* animation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
CGMutablePathRef path = CGPathCreateMutable();

int height = -heightFactor + arc4random() % 40 - 20;
int xOffset = frame.origin.x;
int yOffset = frame.origin.y;

CGPoint p1 = CGPointMake(xOffset, height * 0 + yOffset);
CGPoint p2 = CGPointMake(xOffset, height * 1 + yOffset);
CGPoint p3 = CGPointMake(xOffset, height * 2 + yOffset);
CGPoint p4 = CGPointMake(xOffset, height * 2 + yOffset);

CGPathMoveToPoint(path, NULL, p1.x, p1.y);

if (arc4random() % 2) {
CGPathAddQuadCurveToPoint(path, NULL, p1.x - arc4random() % waveWidth, p1.y + height / 2.0, p2.x, p2.y);
CGPathAddQuadCurveToPoint(path, NULL, p2.x + arc4random() % waveWidth, p2.y + height / 2.0, p3.x, p3.y);
CGPathAddQuadCurveToPoint(path, NULL, p3.x - arc4random() % waveWidth, p3.y + height / 2.0, p4.x, p4.y);
}
else {
CGPathAddQuadCurveToPoint(path, NULL, p1.x + arc4random() % waveWidth, p1.y + height / 2.0, p2.x, p2.y);
CGPathAddQuadCurveToPoint(path, NULL, p2.x - arc4random() % waveWidth, p2.y + height / 2.0, p3.x, p3.y);
CGPathAddQuadCurveToPoint(path, NULL, p3.x + arc4random() % waveWidth, p3.y + height / 2.0, p4.x, p4.y);
}
animation.path = path;
animation.calculationMode = kCAAnimationCubicPaced;
CGPathRelease(path);
return animation;
}
  1. 便捷调用
    并不是所有开发者都想一次次的写所有参数,所以应该提供便捷的调用方法.
+(CAKeyframeAnimation*)curveAnimationWithFrame:(CGRect)frame{

  return  [GUIFrameAnimation createAnimationWithFrame:frame waveWidth:50 heightFactor:100];
}

结语

这只是封装, 远远不够一份可读性高代码的要求. 应该继续进行重构. 但是不在现在讨论的范畴 .所以暂不讨论了.