-----------android培训、java培训、iOS培训、.Net培训、期待与您交流!------------
情境2:使用Objective-C的面向对象特性
// main.m
#import <Foundation/Foundation.h>
#import "Graphic.h"
#import "WTriangle.h"
#import "WCircle.h"
#import "WSquare.h"
#import "WTools.h"
#define LENGHT 3
int main(int argc, const char * argv[])
{
@autoreleasepool {
double a,b,c; // a,b,c为三边长
double radius; // radius为圆半径
double width; // width为边长
double circum,area; // circum为图形周长,area为图形面积
NSString *category;
Graphic *graphic[LENGHT]; // 声明一个图形类数组
graphic[0] = [[WTriangle alloc] initWithGname:@"triangle" andCategory:WCategoryRuled]; // 数组的首元素是WTriangle对象
graphic[1] = [[WCircle alloc] initWithGname:@"circle" andCategory:WCategoryRuled]; // 数组的第二个元素是WCircle对象
graphic[2] = [[WSquare alloc] initWithGname:@"square" andCategory:WCategoryRuled]; // 数组的第三个元素是WSquare对象
NSLog(@"Please input three length of triange:");
scanf("%lf,%lf,%lf",&a,&b,&c);
// a,b,c三条边是否能构成一个三角形
if ([(WTriangle *)graphic[0] isValidA: a B:b andC:c])
{
[(WTriangle *)graphic[0] setA:a B:b andC:c];
} // < 1 > 处测试封装
NSLog(@"Please input the radius of circle:");
scanf("%lf",&radius);
[(WCircle *)graphic[1] setRadius:radius];
NSLog(@"Please input the length of square:");
scanf("%lf",&width);
[(WSquare *)graphic[2] setWidth:width];
// < 3 >
for (int i = 0 ; i < LENGHT; i ++) {
circum = [graphic[i] circum];
area = [graphic[i] area];
category = [WTools tranformPrint:[graphic[i] category]];
NSLog(@"\nThe perimeter of %@:%.2lf,area:%.2lf and %@",graphic[i].gname,circum,area,category);
}
}
return 0;
}
// TypeBean.h
#ifndef Blog01e_TypeBean_h
#define Blog01e_TypeBean_h
// 图形是否规则
typedef enum WCategory {
WCategoryRuled, // 规则图形
WCategoryUnruled // 不规则图形
} WCategory;
#endif
// Graphic.h
// 继承自NSObject类,在这里作为其它类的父类
#import <Foundation/Foundation.h>
#import "TypeBean.h"
@interface Graphic : NSObject
{
NSString *_gname;
WCategory _category;
}
// 类成员变量的getter && setter 方法 < 2 >
- (NSString *) gname;
- (void) setGname:(NSString *)gname;
- (WCategory) category;
- (void) setCategory:(WCategory)category;
// 利用图形名与图形规则进行初始化
- (Graphic *) initWithGname:(NSString *)gname andCategory:(WCategory)category;
// 获得图形周长的方法
- (double) circum;
// 获得图形面积的方法
- (double) area;
@end
// 图形类的实现
// Graphic.m
#import "Graphic.h"
@implementation Graphic
// 类成员变量的getter && setter 方法
- (NSString *) gname
{
return _gname;
}
- (void)setGname:(NSString *)gname
{
self->_gname = gname;
}
- (WCategory) category
{
return _category;
}
- (void) setCategory:(WCategory)category
{
self->_category = category;
}
// 利用图形名与图形规则进行初始化
- (Graphic *) initWithGname:(NSString *)gname andCategory:(WCategory)category
{
if (self = [super init])
{
self.gname = gname;
self.category = category;
}
return self;
}
// 获得图形周长的方法
- (double) circum
{
NSLog(@"子类负责实现这个方法");
return 0.0;
}
// 获得图形面积的方法
- (double) area
{
NSLog(@"子类负责实现这个方法");
return 0.0;
}
@end
// 三角形类的声明
// WTriangle.h
#import "Graphic.h"
@interface WTriangle : Graphic
{
// 三角形的三边长
double _a;
double _b;
double _c;
}
// 成员变量的getter方法
- (double) a;
- (double) b;
- (double) c;
// 同时为_a,_b,_c赋值
- (void) setA:(double)a B:(double)b andC:(double)c;
// 判断三边是否能构成三角形
- (BOOL) isValidA:(double)a B:(double)b andC:(double)c;
@end
// 三角形类的实现 <span style="white-space:pre"> </span> // WTriangle.m
#import "WTriangle.h"
#import <math.h>
@implementation WTriangle
// 成员变量_a,_b,_c的get方法
- (double) a
{
return _a;
}
- (double) b
{
return _b;
}
- (double) c
{
return _c;
}
// 同时为_a,_b,_c赋值
- (void) setA:(double)a B:(double)b andC:(double)c
{
self->_a = a;
self->_b = b;
self->_c = c;<span style="white-space:pre"> </span> // < 2 ><span style="white-space:pre"> </span>
}
// 重写父类的求周长方法
- (double)circum
{
return self.a + self.b + self.c;
}
// 重写父类的求面积方法
- (double)area
{
// p为三角形的半周长
double p = (self.a + self.b + self.c) / 2.0;
// 海伦公式求三角形的面积
double st = sqrt(p * (p - self.a) * (p - self.b) * (p - self.c));
return st;
}
// 判断三边是否能构成三角形
- (BOOL) isValidA:(double)a B:(double)b andC:(double)c;
{
// 如果有一边为负数则返回NO
if ( a < 0 || b < 0 || c < 0)
{
return NO;
}
// 任意两边之和大于第三边
if (a + b > c && a + c > b && b + c > a)
{
return YES;
}
else
{
return NO;
}
}
@end
// 圆形类的声明
// WCircle.h
#import "Graphic.h"
@interface WCircle : Graphic
{
double _radius;
}
// 半径的getter && setter方法
- (double) radius;
- (void)setRadius:(double)radius;
@end
// 圆形类的实现 <span style="white-space:pre"> </span> // WCircle.m
#import "WCircle.h"
#import <math.h>
#define PI 3.14
@implementation WCircle
// 半径的getter && setter方法
- (double) radius
{
return _radius;
}
- (void)setRadius:(double)radius
{
self->_radius = radius;
}
// 重写父类的求周长方法
- (double)circum
{
return 2 * PI * self.radius;
}
// 重写父类的求面积方法
- (double) area
{
return PI * pow(self.radius, 2);
}
@end
// 正方形类的声明
// WSquare.h
#import "Graphic.h"
@interface WSquare : Graphic
{
double _width; // 正方形的边长
}
// 正方形边长的getter && setter方法
- (double) width;
- (void) setWidth:(double)width;
@end
// 正方形类的实现
// WSquare.m
#import "WSquare.h"
@implementation WSquare
// 正方形边长的getter && setter方法
- (double) width
{
return _width;
}
- (void) setWidth:(double)width
{
self->_width = width;
}
// 重写父类的求周长的方法
- (double)circum
{
return 4 * self.width;
}
// 重写父类的求面积的方法
- (double) area
{
return pow(self.width, 2);
}
@end
// 工具类的声明
// WTools.h
#import <Foundation/Foundation.h>
#import "TypeBean.h"
@interface WTools : NSObject
// 将枚举值转换为对应的字符串
+ (NSString *)tranformPrint:(WCategory)category;
@end
// 工具类的实现
// WTools.m
#import "WTools.h"
@implementation WTools
// 将枚举值转换为对应的字符串
+ (NSString *)tranformPrint:(WCategory)category
{
if (category == WCategoryRuled)
{
return @"it's rule";
}
else
{
return @"it's not rule";
}
}
@end
运行结果:
- 封装
在 main.m的 < 1 > 处 添加如下代码
WTriangle *triangle = [[WTriangle alloc] init];
triangle->_a = -1;
Xcode报错
证明对象的成员变量不能直接被修改,且默认的访问修饰符是@protected,保证了对象的成员变量不会获得不合理的值,还有3种访问修饰符@protected,@package,@private,但@package修饰符不常用,所以剩下3个修饰符的开放程度@public > @protected > @private
2. 继承
在这道题中,类WTriangle,WCircle,WSquare继承了类Graphic,而类Graphic继承自类NSObject,因为OC是单继承的,所以子类与父类的关系是多对一,因为类WTriangle,WCircle,
WSquare继承自Graphic类,且成员变量的访问修饰符是@protected,所以子类可以访问父类的成员变量,即在WTriangle.m的 < 2 >添加如下代码
self->_gname = @"Dimend";
Xcode不报错,证明WTriangle类有_gname这个成员变量,通过继承子类得到了父类中得成员变量,实现了代码的复用。反过来从父类到子类的过程看,比如WTriangle需要的是_a,_b,_c三边,而WCircle需要的是_radius,子类可以根据需求扩展父类,而且不需要更改父类的内容。实现了对代码扩展的开放,修改的关闭。
3. 多态
在 main.m的 < 3 > 处 实现了多态的特性,多态的表现是父类的指针指向子类对象,而能够实现多态是因为动态绑定。关于动态绑定的解释百度百科上是这么定义的:指在执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用其相应的方法。
在这里的代码体现在 graphic[0]应该是一个指向Graphic类的指针,但是实际拿到的是一个WTriangle类。调用graphic[0]的area方法,实际被调用的是对象WTriangle的area方法,而不是声明graphic[0]指针的Graphic对象的area方法。
graphic[0] = [[WTriangle alloc] initWithGname:@"triangle" andCategory:WCategoryRuled]; [graphic[i] area];
使用多态可以屏蔽子类对象之间的差异,关注子类对象之间的共同点,让代码简洁。但是多态也有它的局限性,比如main.m中的,graphic[1]在编译期被认为是一个Graphic类对象,所以,如果不使用强制转换
[graphic[1] setRadius:radius];
Xcode 将报
的错误,因为它认为这是一个Graphic类对象,自然找不到setRadius这个方法。
在上面的代码中,出现了一些有待说明的地方。
1. self 与 super 关键字,方法的修饰符 + / -
2. 对象的init方法
3. 父类Graphic的circum与area,不应该实现,因为任何一个具体图形都不应该调用这两个方法
// 获得图形周长的方法
- (double) circum
{
NSLog(@"子类负责实现这个方法");
return 0.0;
}
// 获得图形面积的方法
- (double) area
{
NSLog(@"子类负责实现这个方法");
return 0.0;
}
4. 不同类的setter 与 getter 方法大同小异。