在我心里,面向对象应该是这样的:
“给马一个规则,让它只能走日”设计模式
而MVVM看上去是将方法从VC分离出来,但是并没有这种感觉,所以我就尝试用我想要的方式写了一个象棋棋子“马”,我称这种设计模式为“给马一个规则,让它只能走日”设计模式.
讲之前先说一下WWeChat,其实更新了,只是没写讲解…改动的还是挺多的,代码在这里.
效果图:
Chess.gif
下面讲我这种设计模式(如果你有建议,欢迎指出!)
-
首先我创建了一个
UIButtom
,名字是Chess
顾名思义,这个类是所有棋子的父类
.h
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
|
/**
* 棋子上的Label
*/
@property (nonatomic,strong)UILabel * categoryLabel;
/**
* 棋子的类别 (红,黑)默认为红
*/
@property (nonatomic,assign)BOOL isRed;
/**
* 棋子的状态 (拿起,放下)默认为放下
*/
@property (nonatomic,assign)BOOL isInAir;
/**
* 每格的宽度
*/
@property (nonatomic,assign)CGFloat rowWidth;
/**
* 目前的行列
*/
@property (nonatomic,copy)NSIndexPath * index;
- (instancetype)initWithRowWidth:(CGFloat)rowWidth andRowLine:(NSIndexPath *)index;
|
.m
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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
- (instancetype)initWithRowWidth:(CGFloat)rowWidth andRowLine:(NSIndexPath *)index
{
if (self = [super init])
{
_isRed = YES;
_isInAir = NO;
_index = index;
_rowWidth = rowWidth;
self.backgroundColor = [UIColor clearColor];
//行
NSInteger row = index.row;
//列
NSInteger line = index.section;
if (row > 5)
{
self.frame = CGRectMake(row * rowWidth - rowWidth/2.0 , line * rowWidth - rowWidth/2.0 + rowWidth, rowWidth, rowWidth);
}
else
{
self.frame = CGRectMake(row * rowWidth - rowWidth/2.0, line * rowWidth - rowWidth/2.0,rowWidth, rowWidth);
}
self.categoryLabel = ({
UILabel * categoryLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, rowWidth, rowWidth)];
categoryLabel.textColor = _isRed == YES ? [UIColor redColor] : [UIColor blackColor];
categoryLabel.textAlignment = NSTextAlignmentCenter;
categoryLabel.adjustsFontSizeToFitWidth = YES;
categoryLabel.backgroundColor = [UIColor whiteColor];
categoryLabel.layer.cornerRadius = rowWidth/2.0;
categoryLabel.clipsToBounds = YES;
categoryLabel.layer.borderColor = [UIColor grayColor].CGColor;
categoryLabel.layer.borderWidth = 2;
categoryLabel;
});
[self addSubview:_categoryLabel];
[self addTarget:self action:@selector(btnClick:) forControlEvents:UIControlEventTouchUpInside];
}
return self;
}
- (void)btnClick:(UIButton *)sender
{
self.isInAir = !self.isInAir;
if (self.isInAir == YES)
{
self.categoryLabel.backgroundColor = [UIColor blackColor];
}
else
{
self.categoryLabel.backgroundColor = [UIColor whiteColor];
}
NSLog(@"%@",_isInAir == YES?@"拿起":@"放下");
}
- (void)setIsRed:(BOOL)isRed
{
_isRed = isRed;
_categoryLabel.textColor = _isRed == YES ? [UIColor redColor] : [UIColor blackColor];
}
|
通过这些代码,棋子获得了被拿起、放下以及分红方、黑方的能力.
-
然后给它创建一个类别
Chess+Move
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
|
- (void)moveToIndex:(NSIndexPath *)index
{
[UIView animateWithDuration:0.5 animations:^{
//行
NSInteger row = index.row;
//列
NSInteger line = index.section;
if (row > 5)
{
self.frame = CGRectMake(line * self.rowWidth - self.rowWidth/2.0 , row * self.rowWidth - self.rowWidth/2.0 , self.rowWidth, self.rowWidth);
}
else
{
self.frame = CGRectMake(line * self.rowWidth - self.rowWidth/2.0, row * self.rowWidth - self.rowWidth/2.0,self.rowWidth, self.rowWidth);
}
}
completion:^(BOOL finished)
{
self.isInAir = NO;
self.categoryLabel.backgroundColor = [UIColor whiteColor];
self.index = index;
}];
}
|
让棋子获得任意移动的能力,不写在Chess
里面,而是写到Chess+Move
里面,我感觉更符合面向对象。
-
现在
Chess
已经可以了,现在创建一个马创建
Chess
的子类House
,获得棋子的基本能力,
1
2
3
4
5
6
7
|
#import "Chess.h"
@interface House : Chess
- (void)newChess;
@end
|
1
2
3
4
5
|
//House里面只要给Label一个text就够了.
- (void)newChess
{
self.categoryLabel.text = @"马";
}
|
-
创建
House+rule
,让马只能走日的规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
- (BOOL)canMoveToIndex:(NSIndexPath *)index
{
NSInteger toRow = index.row;
NSInteger toLine = index.section;
NSInteger fromRow = self.index.row;
NSInteger fromLine = self.index.section;
if(ABS(toLine - fromLine) == 1 & ABS(toRow - fromRow) == 2)
{
return YES;
}
else if(ABS(toLine - fromLine) == 2 & ABS(toRow - fromRow) == 1)
{
return YES;
}
else
{
return NO;
}
}
|
-
创建棋盘
UIView
类的Map
.h
1
2
3
4
5
6
7
|
/**
* 每格的宽度
*/
@property (nonatomic,assign)CGFloat rowWidth;
- (instancetype)initWithStartPt:(CGPoint)pt andRowWidth:(CGFloat)rowWidth;
|
.m
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
32
33
34
35
36
37
38
39
40
41
42
43
|
- (instancetype)initWithStartPt:(CGPoint)pt andRowWidth:(CGFloat)rowWidth
{
if (self = [super init])
{
_rowWidth = rowWidth;
self.frame = CGRectMake(pt.x, pt.y, rowWidth * 8, rowWidth * 8 + rowWidth);
self.backgroundColor = [UIColor grayColor];
//画列线
for (int j = 0 ; j < 2; j++)
{
for (int i = 0 ; i < 9; i++)
{
UIView * line = [[UIView alloc]init];
line.backgroundColor = [UIColor whiteColor];
if (j == 0)
{
line.frame =CGRectMake(i * rowWidth - 1 , 0, 2 , (self.frame.size.height - rowWidth)/2.0);
}
else
{
line.frame =CGRectMake(i * rowWidth - 1 , (self.frame.size.height - rowWidth)/2.0 + rowWidth, 2 , (self.frame.size.height - rowWidth)/2.0);
}
[self addSubview:line];
}
}
//画行线
for (int i = 0; i < 10; i++)
{
UIView * line = [[UIView alloc]init];
line.frame = CGRectMake(0, i * rowWidth - 1 , self.frame.size.width , 2);
line.backgroundColor = [UIColor whiteColor];
[self addSubview:line];
}
}
return self;
}
|
这里看看就行了,就是画线。
-
走马
在
Map
中创建一个点击事件
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
32
33
34
35
36
37
|
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
{
UITouch * touch = [touches anyObject];
CGPoint pt = [touch locationInView:self];
//行
NSInteger row = floor((pt.y - _rowWidth/2.0) / _rowWidth) + 1 ;
//列
NSInteger line = floor((pt.x - _rowWidth/2.0) / _rowWidth) + 1 ;
for (UIView * view in self.subviews)
{
if ([view isKindOfClass:[Chess class]])
{
//马
if ([view isKindOfClass:[House class]])
{
House * house = (House *)view;
if (house.isInAir == YES)
{
if ([house canMoveToIndex:[NSIndexPath indexPathForRow:row inSection:line]])
{
[house moveToIndex:[NSIndexPath indexPathForRow:row inSection:line]];
}
}
}
//其他棋子
else
{
}
}
}
NSLog(@"row:%ld line:%ld",row,line);
}
|
整个项目我都用了一个方法来避开复杂的位置计算,将虚拟的棋盘,化成一部分一部分,根据行、列来确定棋子位置.
总结
可以看出,我在这里通过类别和继承来使一个Button变成了一个只能走日的棋子“马”,这样的模式,我感觉更符合面向对象的思想.
做其他棋子也会非常简单,只需要再创建属于其他棋子的类别(规则)就行了。
还是那句话!有建议欢迎指出,大家一起讨论!