九宫格之模型,封装初体验
2015-10-01 16:42
573 查看
曾经以为面向对象开发,无非就是封装成类嘛,没什么不同,但是今天在做这个小程序的时候,稍微体会到了一点所谓的,面向对象开发.
以前写C的程序,往往是顺序而过程的编程.像融入到代码中一样,不需要太多的思想.
然而在面向对象编程的时候,需要站在上帝视角上,俯瞰整个项目,着手一个对象模型的构造,在不断的构造对象的时候,实现封装.
===============
用纯代码的方式,实现这样一个小程序
第一步,图标放到Images.xcassets文件中就行了, 因为文件不是太大,不会影响内存的使用, 然后将图片的描述信息,放到Plist文件中,这也相当于实现了一次小封装.
将这些资源准备好, 就可以进行读取了.
从plist文件中就能看出,我们代码中是用一个NSArray 数组接收plist文件中的信息的.
再为setter设计功能的时候有不同的方式,也体现了不同程度的封装.
1.我们的目的是从文件中读取相应的控件描述信息给appInfo, 那么我们就直接一点,直接将文件里面读取到的内容放到appinfo中咯
这样就OK了,但是这样在后续使用的时候, 很依赖该数组中具体封装的属性 "icon" , "name" 如果后期我在添加其他的属性,或者修改, 那么就需要到源码中不断修改.
因为我们需要不断使用 数组和字典的语法 给控件赋值 而他们的语法明显很依赖 属性
我们应该始终秉承着这样一个原则,我们所写的主代码就是客户, 而我们图片啊,控件啊,描述信息啊就是我们商品, 任由我们的商品配方如何变化,客户要做的就是消费我们的商品
而这具体消费也是我们提供给客户对这件商品的使用方法, 比如对这件商品 吃,喝, 踹等....当我们的配方变化了的时候,这一系列消费动作还是不变的.
比如,我们给客户提供了,对文件的读取,那么我们就仅仅 一个读取接口,对于接口中配方的变化,我们不让客户知道,客户就知道读取OK了行了.
2. 我们把这几个属性进行封装,封装成一个类,这样做,我们至少以可以使用 点语法,当然这样和上面没有太大的区别,还是有很强的依赖性
也就是说我们让
首先创建类文件
3. 在将文件中的信息封装成类后, 仍然没有解决过度依赖的问题, 那么我们在类中定义类方法,这样我们在为数组加载数据的时候,只需要调用类方法,让类方法返回读取到的数据即可.
这样我们的setter方法实现了低耦合, 高内聚性,
=========================
好了第一部分完成了.
下一步看一下控件的方面. 对于控件方面,有两种方式,第一种每个控件单独布局,并计算坐标点.
这个控件分为三部分, 图片控件, label控件还有一个button按钮控件
那么三个控件相对与屏幕的坐标需要挨个计算这很麻烦,我们可以先生成一个基于view的子控件,然后将三个控件在添加到该子控件中,这样他们的坐标就是基于该子控件了
UIView * subView = [[UIView alloc] init];
[self.view addSubview: subView];
我们在取得了appInfos中一个对象后,就取得了整个控件的描述信息,只要再写一个方法,去分别生成三个子控件,并为该方法传递一个描述控件的对象.
由于我们对描述信息就行了封装,所以就不需要传递依赖性高的字典了.
首先写一个取数组中描述信息的对象的方法, 然后在该方法中调用子控件生成的方法
- (void) newBox{
CZAppinfo * appinfo = 取一个对象
设置先subView的坐标
传递参数
- (void) addSubView: (UIView *) subView appdesc: (CZAppinfo *) appinfo{
//不要忘记将三个子控件添加到subView上
[subView addSubview: 控件名字_View];
//每个控件都需要添加
}
}
这样就完成了整个界面的布局.
还有一种更简洁的方式去完成这个过程,就是利用 xib布局
创建xib文件
可以看出来, 我们把这三个控件封装到一起, 最外层是一个view控件, 这个过程也需要将三个控件添加为view子控件, 最后为view创建实现类,就像main.storyboard
实现UIView类
那xib中的view实现CZAppinfoView类(自定义控件类)
这样我们就可以在实现类中定义控件属性, 方法 并能创建基于该类的控件, 基于该类创建出来的控件就是上面我们自己自定义的控件了.
- (void) newBox{
CZAppinfo * appinfo = 取一个对象
创建自定类的控件, 设置坐标.
}
为了提高独立性,我们再在CZAppInfoView类中添加一个属性,用于描述各控件信息,这样我们可以随时使用这些信息,因为他们和控件都是类的一部分
@class CZAppinfo;
@interface CZAppInfoView : UIView
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
- (IBAction)loadDown:(UIButton *)sender;
@property (weak, nonatomic) IBOutlet UILabel *nameView;
@property (nonatomic, strong) CZAppinfo * appInfo; //每个控件都会由相应的描述信息,而不依赖控件本身
+(instancetype) loadCZappinfoView;
@end
这里有一点需要注意, 我们在创建该类对象时候,其实是从该xib文件中读取对象控件的,我们需要给它实现下相应的读取方法
+(instancetype) loadCZappinfoView{
NSBundle * bundle = [NSBundle mainBundle];
//取出来的是整个组合起来的控件
CZAppInfoView * subView = [[bundle loadNibNamed: @"CZAppInfoView" owner: nil options: nil] lastObject];
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>
return subView;
}
可以看到
CZAppInfoView * subView = [[bundle loadNibNamed: @"CZAppInfoView" owner: nil options: nil] lastObject];
我们看下这个方法的定义
这行代码 和我们平时创建对象时不同,我们是使用 loadNibNamed去读取的. 而且从xib中读取的控件组合是一个数组的形式存放的(三个控件为一个元素)
而我们需要的是整个控件,所以我们用lastObject返回这整个控件(也可以用下标, 里面就一个元素). 一定要注意这个生成过程.
还有不要忘记了,我们在该类中还有一个属性
@property (nonatomic, strong) CZAppinfo * appInfo; //每个控件都会由相应的描述信息,而不依赖控件本身
我们还需要为该类中的appInfo控件描述属性 重写setter方法, 这样当我们从- (void) newBox; 方法中取得数组中的描述信息的对象后, 可以直接为CZAppInfoView所生成的
控件, 添加描述信息.
- (void) setAppInfo:(CZAppinfo *)appInfo{
_appInfo = appInfo;
self.nameView.text = appInfo.name;
self.iconView.image = [UIImage imageNamed: appInfo.icon];
}
完整的创建控件主代码部分
- (void) newBox{
CGFloat subViewW = 100;
CGFloat subViewH = 100;
CGFloat marginX = (self.view.frame.size.width - 3 * subViewW) / 4;
CGFloat marginY = 20;
for(int i = 0; i < self.appInfos.count; i ++){
int row = i / 3;
int column = i % 3;
CGFloat subViewX = marginX + column * (marginX + subViewW);
CGFloat subViewY = 30 + row * (marginY + subViewH);
CZAppInfoView * subView = [CZAppInfoView loadCZappinfoView]; //高度封装后,创建从xib文件中的控件
[self.view addSubview: subView];
subView.frame = CGRectMake(subViewX, subViewY, subViewW, subViewH);
CZAppinfo * appinfo = self.appInfos[i];
subView.appInfo = appinfo; //通过简单的setter方法完成描述信息的录入
}
}
================================================================
做这个小程序,其实学到更多的是 封装的思想, 这远远大于程序本身.
1.在对plist文件中的字典 进行封装成对象
2.对xib文件中的控件组合 封装成对象.
3.对一系列依赖度过高的代码,独立封装成方法.
以前写C的程序,往往是顺序而过程的编程.像融入到代码中一样,不需要太多的思想.
然而在面向对象编程的时候,需要站在上帝视角上,俯瞰整个项目,着手一个对象模型的构造,在不断的构造对象的时候,实现封装.
===============
用纯代码的方式,实现这样一个小程序
第一步,图标放到Images.xcassets文件中就行了, 因为文件不是太大,不会影响内存的使用, 然后将图片的描述信息,放到Plist文件中,这也相当于实现了一次小封装.
将这些资源准备好, 就可以进行读取了.
从plist文件中就能看出,我们代码中是用一个NSArray 数组接收plist文件中的信息的.
@property (nonatomic, strong) NSArray *appInfos;
再为setter设计功能的时候有不同的方式,也体现了不同程度的封装.
1.我们的目的是从文件中读取相应的控件描述信息给appInfo, 那么我们就直接一点,直接将文件里面读取到的内容放到appinfo中咯
NSBundle *bundle = [NSBundle mainBundle]; NSString *path = [bundle pathForResource:@"app" ofType:@"plist"]; _appInfos = [NSArray arrayWithContentsOfFile: path];
这样就OK了,但是这样在后续使用的时候, 很依赖该数组中具体封装的属性 "icon" , "name" 如果后期我在添加其他的属性,或者修改, 那么就需要到源码中不断修改.
因为我们需要不断使用 数组和字典的语法 给控件赋值 而他们的语法明显很依赖 属性
我们应该始终秉承着这样一个原则,我们所写的主代码就是客户, 而我们图片啊,控件啊,描述信息啊就是我们商品, 任由我们的商品配方如何变化,客户要做的就是消费我们的商品
而这具体消费也是我们提供给客户对这件商品的使用方法, 比如对这件商品 吃,喝, 踹等....当我们的配方变化了的时候,这一系列消费动作还是不变的.
比如,我们给客户提供了,对文件的读取,那么我们就仅仅 一个读取接口,对于接口中配方的变化,我们不让客户知道,客户就知道读取OK了行了.
2. 我们把这几个属性进行封装,封装成一个类,这样做,我们至少以可以使用 点语法,当然这样和上面没有太大的区别,还是有很强的依赖性
也就是说我们让
@property (nonatomic, strong) NSArray *appInfos;中的数组中存放的是对象,而不是简单几个属性.
首先创建类文件
3. 在将文件中的信息封装成类后, 仍然没有解决过度依赖的问题, 那么我们在类中定义类方法,这样我们在为数组加载数据的时候,只需要调用类方法,让类方法返回读取到的数据即可.
- (instancetype) initWithDic: (NSDictionary *) dic{ if(self = [self init]){ self.name = dic[@"name"]; self.icon = dic[@"icon"]; } return self; } + (instancetype) appInfoWithDic: (NSDictionary *) dic{ return [[self alloc] initWithDic: dic]; } + (NSArray *) appINfoList{ NSBundle *bundle = [NSBundle mainBundle]; NSString *path = [bundle pathForResource:@"app" ofType:@"plist"]; NSArray *dicArray = [NSArray arrayWithContentsOfFile:path]; NSMutableArray *tmpArray = [NSMutableArray array]; // 字典转换模型 for (NSDictionary *dic in dicArray) { CZAppinfo *appInfo = [CZAppinfo appInfoWithDic: dic]; [tmpArray addObject:appInfo]; } return tmpArray; }
这样我们的setter方法实现了低耦合, 高内聚性,
- (NSArray *) appInfos{ if (_appInfos == nil) { _appInfos = [CZAppinfo appINfoList]; } return _appInfos; }
=========================
好了第一部分完成了.
下一步看一下控件的方面. 对于控件方面,有两种方式,第一种每个控件单独布局,并计算坐标点.
这个控件分为三部分, 图片控件, label控件还有一个button按钮控件
那么三个控件相对与屏幕的坐标需要挨个计算这很麻烦,我们可以先生成一个基于view的子控件,然后将三个控件在添加到该子控件中,这样他们的坐标就是基于该子控件了
UIView * subView = [[UIView alloc] init];
[self.view addSubview: subView];
我们在取得了appInfos中一个对象后,就取得了整个控件的描述信息,只要再写一个方法,去分别生成三个子控件,并为该方法传递一个描述控件的对象.
由于我们对描述信息就行了封装,所以就不需要传递依赖性高的字典了.
首先写一个取数组中描述信息的对象的方法, 然后在该方法中调用子控件生成的方法
- (void) newBox{
CZAppinfo * appinfo = 取一个对象
设置先subView的坐标
传递参数
- (void) addSubView: (UIView *) subView appdesc: (CZAppinfo *) appinfo{
//不要忘记将三个子控件添加到subView上
[subView addSubview: 控件名字_View];
//每个控件都需要添加
}
}
这样就完成了整个界面的布局.
还有一种更简洁的方式去完成这个过程,就是利用 xib布局
创建xib文件
可以看出来, 我们把这三个控件封装到一起, 最外层是一个view控件, 这个过程也需要将三个控件添加为view子控件, 最后为view创建实现类,就像main.storyboard
实现UIView类
那xib中的view实现CZAppinfoView类(自定义控件类)
这样我们就可以在实现类中定义控件属性, 方法 并能创建基于该类的控件, 基于该类创建出来的控件就是上面我们自己自定义的控件了.
- (void) newBox{
CZAppinfo * appinfo = 取一个对象
创建自定类的控件, 设置坐标.
}
为了提高独立性,我们再在CZAppInfoView类中添加一个属性,用于描述各控件信息,这样我们可以随时使用这些信息,因为他们和控件都是类的一部分
@class CZAppinfo;
@interface CZAppInfoView : UIView
@property (weak, nonatomic) IBOutlet UIImageView *iconView;
- (IBAction)loadDown:(UIButton *)sender;
@property (weak, nonatomic) IBOutlet UILabel *nameView;
@property (nonatomic, strong) CZAppinfo * appInfo; //每个控件都会由相应的描述信息,而不依赖控件本身
+(instancetype) loadCZappinfoView;
@end
这里有一点需要注意, 我们在创建该类对象时候,其实是从该xib文件中读取对象控件的,我们需要给它实现下相应的读取方法
+(instancetype) loadCZappinfoView{
NSBundle * bundle = [NSBundle mainBundle];
//取出来的是整个组合起来的控件
CZAppInfoView * subView = [[bundle loadNibNamed: @"CZAppInfoView" owner: nil options: nil] lastObject];
<span style="white-space:pre"> </span> <span style="white-space:pre"> </span>
return subView;
}
可以看到
CZAppInfoView * subView = [[bundle loadNibNamed: @"CZAppInfoView" owner: nil options: nil] lastObject];
我们看下这个方法的定义
这行代码 和我们平时创建对象时不同,我们是使用 loadNibNamed去读取的. 而且从xib中读取的控件组合是一个数组的形式存放的(三个控件为一个元素)
而我们需要的是整个控件,所以我们用lastObject返回这整个控件(也可以用下标, 里面就一个元素). 一定要注意这个生成过程.
还有不要忘记了,我们在该类中还有一个属性
@property (nonatomic, strong) CZAppinfo * appInfo; //每个控件都会由相应的描述信息,而不依赖控件本身
我们还需要为该类中的appInfo控件描述属性 重写setter方法, 这样当我们从- (void) newBox; 方法中取得数组中的描述信息的对象后, 可以直接为CZAppInfoView所生成的
控件, 添加描述信息.
- (void) setAppInfo:(CZAppinfo *)appInfo{
_appInfo = appInfo;
self.nameView.text = appInfo.name;
self.iconView.image = [UIImage imageNamed: appInfo.icon];
}
完整的创建控件主代码部分
- (void) newBox{
CGFloat subViewW = 100;
CGFloat subViewH = 100;
CGFloat marginX = (self.view.frame.size.width - 3 * subViewW) / 4;
CGFloat marginY = 20;
for(int i = 0; i < self.appInfos.count; i ++){
int row = i / 3;
int column = i % 3;
CGFloat subViewX = marginX + column * (marginX + subViewW);
CGFloat subViewY = 30 + row * (marginY + subViewH);
CZAppInfoView * subView = [CZAppInfoView loadCZappinfoView]; //高度封装后,创建从xib文件中的控件
[self.view addSubview: subView];
subView.frame = CGRectMake(subViewX, subViewY, subViewW, subViewH);
CZAppinfo * appinfo = self.appInfos[i];
subView.appInfo = appinfo; //通过简单的setter方法完成描述信息的录入
}
}
================================================================
做这个小程序,其实学到更多的是 封装的思想, 这远远大于程序本身.
1.在对plist文件中的字典 进行封装成对象
2.对xib文件中的控件组合 封装成对象.
3.对一系列依赖度过高的代码,独立封装成方法.
相关文章推荐
- 自己简单封装的一个CDialog类实例
- PHP类的封装与继承详解
- javascript封装简单实现方法
- 封装好的一个万能检测表单的方法
- jquery datatable后台封装数据示例代码
- c#基础学习之封装
- 纯JavaScript实现的兼容各浏览器的添加和移除事件封装
- PHP面向对象三大特点学习(充分理解抽象、封装、继承、多态)
- javascript的函数、创建对象、封装、属性和方法、继承
- 异步的SQL数据库封装详解
- 深入解析C++编程中类的封装特性
- C++封装IATHOOK类实例
- javascript封装 Cookie 应用接口
- WebService 的简单封装接口调用方法
- Node.js中对通用模块的封装方法
- 原生Javascript封装的一个AJAX函数分享
- javascript 面向对象封装与继承
- JavaScript的模块化:封装(闭包),继承(原型) 介绍
- JavaScript 封装一个tab效果源码分享
- C++封装远程注入类CreateRemoteThreadEx实例