1.桥接模式
定义
将抽象部分与它的实现部分分离,使它们都可以独立地变化。
原理
抽象层与实现层相分离, 抽象层定义了供客户端调用的抽象接口, 实现层提供了具体的逻辑. 实现类的引用被封装到抽象层的实例中,桥接就形成,降低耦合性
理解
原先一个类型的电视机对应一个遥控器,利用桥接模式就是把每个遥控器共有的部分抽取出来,定义遥控器
特点
- 将依赖具体的实现, 改为依赖抽象. 起到一个松耦合的作用
- 分离了接口和实现部分
- 提高了扩展性
demo
就以上面的电视机遥控器为案例,这里有两个电视机xiaomi和kj,两个遥控器XiaoMiRemote和KJRemote,每个遥控器有几个方法
桥接前
XiaoMiTV
@implementation XiaoMiTV
- (void)loadCommand:(NSString *)command {
// 点击了之后, 需要实现的业务逻辑
NSLog(@"您按的是:----%@",command);
}
@end
XiaoMiRemote
#import "XiaoMiRemote.h"
@implementation XiaoMiRemote
- (void)up {
[self.TV loadCommand:@"up"];
}
- (void)down {
[self.TV loadCommand:@"down"];
}
- (void)left {
[self.TV loadCommand:@"left"];
}
- (void)right {
[self.TV loadCommand:@"right"];
}
@end
KJTV
@implementation KJTV
- (void)loadCommandKJ:(NSString *)commandKJ {
// 点击了之后, 需要实现的业务逻辑
NSLog(@"您按的是KJ:----%@",commandKJ);
}
@end
KJRemote
@implementation KJRemote
- (void)up {
[self.TV loadCommandKJ:@"up"];
}
- (void)down {
[self.TV loadCommandKJ:@"down"];
}
- (void)left {
[self.TV loadCommandKJ:@"left"];
}
- (void)right {
[self.TV loadCommandKJ:@"right"];
}
@end
调用的viewController
#import "ViewController.h"
#import "XiaoMiTV.h"
#import "XiaoMiRemote.h"
#import "KJTV.h"
#import "KJRemote.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// 小米电视
XiaoMiTV *TV = [[XiaoMiTV alloc] init];
XiaoMiRemote *remote = [[XiaoMiRemote alloc] init];
remote.TV = TV;
[remote up];
[remote down];
// KJ电视
KJTV *TV2 = [[KJTV alloc] init];
KJRemote *remote2 = [[KJRemote alloc] init];
remote2.TV = TV2;
[remote2 up];
[remote2 down];
}
@end
桥接模式抽取
思路
把遥控器抽象出一个父类, 把电视机也抽象出一个父类。用抽象的控制器对抽象的电视机类进行引用,具体的实现由他们的子类来做.
抽象出的TV类
@interface TV : NSObject
// 电视机提供给外界的方法
- (void)loadCommand:(NSString *)command;
@end
#import "TV.h"
@implementation TV
// 抽象方法
- (void)loadCommand:(NSString *)command {}
@end
抽象出的遥控器父类
@interface Remote : NSObject
@property (nonatomic, strong) TV *tv;
- (void)setCommand:(NSString *)command;
@end
@implementation Remote
- (void)setCommand:(NSString *)command {
[self.tv loadCommand:command];
}
@end
遥控器的实现
//这里遵循开闭原则:一个软件实体如类、模块和函数应该对扩展开放,对修改关闭
@interface SubRemote : Remote
/**方向控制按钮*/
- (void)up;
- (void)down;
- (void)left;
- (void)right;
@end
@implementation SubRemote
- (void)up {
[super setCommand:@"up"];
}
- (void)down {
[super setCommand:@"down"];
}
- (void)left {
[super setCommand:@"left"];
}
- (void)right {
[super setCommand:@"right"];
}
@end
电视机的实现
@implementation TVXiaoMi
- (void)loadCommand:(NSString *)command {
if ([command isEqualToString:@"up"]) {
NSLog(@"您按的是XM:----%@",command);
}
else if ([command isEqualToString:@"down"]) {
NSLog(@"您按的是XM:----%@",command);
}
else if ([command isEqualToString:@"left"]) {
NSLog(@"您按的是XM:----%@",command);
}
else if ([command isEqualToString:@"right"]) {
NSLog(@"您按的是XM:----%@",command);
}
else {
NSLog(@"超出范围");
}
}
@end
康佳
@implementation TVKJ
- (void)loadCommand:(NSString *)command {
if ([command isEqualToString:@"up"]) {
NSLog(@"您按的是KJ:----%@",command);
}
else if ([command isEqualToString:@"down"]) {
NSLog(@"您按的是KJ:----%@",command);
}
else if ([command isEqualToString:@"left"]) {
NSLog(@"您按的是KJ:----%@",command);
}
else if ([command isEqualToString:@"right"]) {
NSLog(@"您按的是KJ:----%@",command);
}
else {
NSLog(@"超出范围");
}
}
@end
调用
// 遥控器调用康佳电视
SubRemote *subremote = [[SubRemote alloc] init];
subremote.tv = [[TVKJ alloc] init];
[subremote up];
// 遥控器调用小米电视
subremote.tv = [[TVXiaoMi alloc] init];
[subremote down];
[subremote right];
可以看到一个遥控器可以调用多个电视机,解耦实现
2.工厂模式
工厂模式分为三种简单工厂, 工厂方法, 抽象工厂。
简单工厂
简单工厂模式其实不是一个设计模式,反而比较像一种编程习惯。主要我们定义一个非常简单的类主要负责帮我们生产不同的产品。
demo
FruitsFactory工厂类
#import "Apple.h"
#import "Orange.h"
#import "Banana.h"
// 外界传进来的类型.
typedef NS_ENUM(NSInteger) {
kApple,
kOrange,
kBanana
}FruitsType;
@interface FruitsFactory : NSObject
// 创建水果的工厂
+ (Fruits *)fruitsFactory:(FruitsType)type;
@end
#import "FruitsFactory.h"
@implementation FruitsFactory
+ (Fruits *)fruitsFactory:(FruitsType)type {
// 创建对象
Fruits *fruits = nil;
switch (type) {
case kApple:
fruits = [[Apple alloc] init];
break;
case kOrange:
fruits = [[Orange alloc] init];
break;
case kBanana:
fruits = [[Banana alloc] init];
break;
default:
break;
}
return fruits;
}
@end
水果父类
@interface Fruits : NSObject
- (void)sweet; /**< 甜的 */
- (void)poorTaste; /**< 不好吃 */
@end
@implementation Fruits
- (void)sweet {}
- (void)poorTaste {}
@end
子类的实现,这里就写苹果了,其他类似
//遵循了开闭原则
@interface Apple : Fruits
- (void)freshApple; /**< 新鲜的苹果 */
@end
@implementation Apple
- (void)sweet {
NSLog(@"Apple 非常甜");
}
- (void)poorTaste {
NSLog(@"Apple 不好吃");
}
- (void)freshApple {
NSLog(@"Apple 新鲜的水果");
}
@end
viewcontroller的调用
- (void)viewDidLoad {
[super viewDidLoad];
// 创建出水果,在工厂方法里面
Fruits *fruits = [FruitsFactory fruitsFactory:kApple];
[fruits sweet];
// 创建橘子
Orange *orange = (Orange *)[FruitsFactory fruitsFactory:kOrange];
[orange acidOrange];
}
工厂方法模式
定义创建对象的接口, 让子类觉得实例化哪一个类, 一个类要实例的时候, 被延迟到了子类里面进行实现。
他是对多个产品进行抽象
特点
每个工厂只操作自己对应的类,别的类他不管
demo
定义一个工厂超类和一个颜色超类,然后每个颜色的工厂类实现
这里只写红色的相关,蓝色那个和红色类似,就不写了
颜色工厂超类
// Generator 相当于是一个工厂
#import <Foundation/Foundation.h>
#import "RedView.h"
#import "BlueView.h"
@interface ColorViewGenerator : NSObject
- (ColorView *)colorViewWithFrame:(CGRect)frame;
@end
@implementation ColorViewGenerator
- (ColorView *)colorViewWithFrame:(CGRect)frame {
return [[ColorView alloc] initWithFrame:frame];
}
@end
RedViewGenerator
@implementation RedViewGenerator
- (ColorView *)colorViewWithFrame:(CGRect)frame {
return [[RedView alloc] initWithFrame:frame];
}
@end
颜色超类ColorView
@implementation ColorView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
[self setBackgroundColor:[UIColor grayColor]];
}
return self;
}
@end
红色类RedView
@implementation RedView
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.backgroundColor = [UIColor redColor];
}
return self;
}
@end
调用方法:
// 1.创建抽象的工厂类
ColorViewGenerator *colorGen = [[BlueViewGenerator alloc] init];
CGRect rect = CGRectMake(0, 0, 320, 600);
ColorView *blueView = [colorGen colorViewWithFrame:rect];
// 2. 添加进去
[self.view addSubview:blueView];
抽象工厂
抽象工厂方法:对工厂抽象
定义:为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们的具体类。
类型:创建类模式
demo
创建抽象工厂
#import "ColorViewFactory.h"
@implementation ColorViewFactory
// 生产颜色的view
+ (UIView *)colorView {
return nil;
}
// 生产UIButton
+ (UIButton *)buttonView {
return nil;
}
@end
抽象工厂的两个子类,只写red
#import "RedViewFactory.h"
#import "RedButton.h"
#import "RedSubView.h"
@implementation RedViewFactory
+ (UIView *)colorView {
return [[RedSubView alloc] init];
}
+ (UIButton *)buttonView {
return [RedButton buttonWithType:UIButtonTypeCustom];
}
@end
view和button就是普通的创建,重点在调用
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
UIView *red = [RedViewFactory colorView];
UIButton *btn = [RedViewFactory buttonView];
[self.view addSubview:btn];
[self.view addSubview:red];
}
@end
抽象工厂模式与工厂方法模式的区别
抽象工厂
1.通过对象组合创建抽象产品
2.创建多个系列的产品
3.必须要修改父类的接口才能支持新的产品
工厂方法
1.通过类继承创建抽象产品
2.创建一种产品
3.子类化创建并重写工厂方法以创建新产品
最主要的区别点: 工厂方法: 多个产品抽象 抽象工厂:对工厂抽象
PS NSNumber
NSNumber是一个抽象工厂类
- (void)viewDidLoad {
[super viewDidLoad];
NSNumber *num = [[NSNumber alloc] init];
NSNumber *intNum = [NSNumber numberWithInt:97];
NSNumber *floatNum = [NSNumber numberWithFloat:1.0f];
NSNumber *boolNum = [NSNumber numberWithBool:YES];
NSLog(@"num = %@",[[num class] description]);
NSLog(@"intNum = %@",[[intNum class] description]);
NSLog(@"floatNum = %@",[[floatNum class] description]);
NSLog(@"boolNum = %@",[[boolNum class] description]);
NSLog(@"转化 = %c",[intNum charValue]);
}
结果
可以看到num是空的,因为他是一个抽象的超类
3.享元模式
定义:相同的数据就拿来共享
享元模式: 1.可共享享元对象. 2. 享元池
- 它主要是减少同一类型对象的大量创建,节约内存空间
-
在iOS开发中的多线程(线程池), UITableViewCell, UICollectionViewCell都是利用这个模式
demo
做一个享元池,创建花朵
创建享元池工厂
#import "Flower.h"
typedef enum {
kRedFlower,
kBlueFlower,
kYellowFlower,
kTotalNumberFlower, // 总共的花的数量
}FlowerType;
@interface FlowerFactory : NSObject
// 享元池(缓存池), 存放享元对象
@property (nonatomic, strong) NSMutableDictionary *flowerPools;
// 创建花的工厂方法
- (Flower *)flowerViewWithType:(FlowerType)type;
// 打印详情类型
- (void)detailsType;
@end
#import "FlowerFactory.h"
@implementation FlowerFactory
- (Flower *)flowerViewWithType:(FlowerType)type {
// 1.懒加载flowerPools. 初始化享元池
if (self.flowerPools == nil) {
self.flowerPools = [[NSMutableDictionary alloc] initWithCapacity:kTotalNumberFlower];
}
// 2. 去享元池里面取
Flower *flower = [self.flowerPools objectForKey:[NSNumber numberWithInteger:type]];
// 3. 如果没取到做判断
if (flower == nil) {
// 1. 创建花
flower = [[Flower alloc] init];
// 2.根据传进来的类型,去选择对应的类型
switch (type) {
case kRedFlower:
flower.flowerColor = @"红色的花";
flower.flowerName = @"红玫瑰";
break;
case kBlueFlower:
flower.flowerColor = @"蓝色的花";
flower.flowerName = @"蓝玫瑰";
break;
case kYellowFlower:
flower.flowerColor = @"黄色的花";
flower.flowerName = @"野菊花";
break;
default:
break;
}
// 3.创建好的花, 添加到享元池
[self.flowerPools setObject:flower forKey:[NSNumber numberWithInt:type]];
}
return flower;
}
- (void)detailsType {
NSArray *array = [self.flowerPools allKeys];
for (NSNumber *key in array) {
Flower* flowre = self.flowerPools[key];
NSLog(@"--keyAddress = %@--- key = %@,---颜色==%@", flowre, key,flowre.flowerColor);
}
}
@end
flower类
@interface Flower : NSObject
@property (nonatomic, copy) NSString *flowerColor; // 花色
@property (nonatomic, copy) NSString *flowerName; // 花名
@end
调用
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
FlowerFactory *factory = [[FlowerFactory alloc] init];
// Flower *flower = [factory flowerViewWithType:kYellowFlower];
// 保存花的数组
NSMutableArray *arrayFlowers = [[NSMutableArray alloc] init];
for (int i = 0; i < 10; ++i) {
// 设置堆积的类型数
FlowerType flowerType = arc4random_uniform(kTotalNumberFlower);
// 使用享元池来创建的
Flower *flower = [factory flowerViewWithType:flowerType];
// Flower *flower = [[Flower alloc] init];
[arrayFlowers addObject:flower];
// 打印详情
[factory detailsType];
}
NSLog(@"flower = %lu", arrayFlowers.count);
}
结果
可以看到是公用的一个对象
优点
假如我把数量改的很大,分别采用享元池和不采用,查看内存
采用享元池如下
不采用享元池如下
可以看到内存节省很多
注意
和UITableViewCell类似,要注意数据的复用