在iOS開發中,簡單工廠模式使用得並不多。但是我認為這是OC反射機制很好的一個例子,所以本文將以計算器為例,講解簡單工廠模式和OC的反射機制。
環境信息:
Mac OS X 10.9
Xcode 5.1.1
正文:
簡單工廠模式的實質是由一個工廠類根據傳入的參數,動態決定應該創建哪一個產品類(這些產品類繼承自一個父類或接口)的實例。該模式中包含的角色及其職責:工廠角色、抽象產品角色、具體產品角色
——百度百科 簡單工廠模式
上面這句話可能不怎麼好理解,我在網上找到了一個例子,可能例子本身不能完全解釋這個設計模式的優點,但是它將角色和職責介紹得很清楚:
一個男生想要請女生吃飯,但是這個男生不會做飯。那麼干脆就到麥當勞去,讓女生自己點喜歡吃的東西就可以了。
在這個例子中,麥當勞就是工廠角色,麥當勞中的產品就是抽象產品角色,薯條、漢堡就是具體產品角色。
按照這種思維模式,我們可以畫出計算器的UML類圖:
簡單工廠模式類圖
根據類圖我們搭框架並進行編碼:
計算器頭文件:Calculate.h
#import <Foundation/Foundation.h>
#import "Operation.h"
@interface Calculate : NSObject
// 一個計算的類方法
+ (float)calculate:(float)number1 number2:(float)number2 operators:(NSString *)operators;
@end
計算器方法實現:Calculate.m
#import "Calculate.h"
@implementation Calculate
+ (float)calculate:(float)number1 number2:(float)number2 operators:(NSString *)operators {
// 使用OC反射獲得一個與字符串同名的類(將在本文後面進行詳細講解)
Class class = NSClassFromString(operators);
// 實例化這個類,並傳入計算器的兩個操作數
Operation *operation = [[class alloc] initWithNumebr1:number1 number2:number2];
// 調用運算方法,並返回結果
return [operation operate];
}
@end
抽象運算類Operation.h
#import <Foundation/Foundation.h>
@interface Operation : NSObject
@property (nonatomic) float number1;
@property (nonatomic) float number2;
- (float)operate; // 運算方法:所有具體運算類都將重寫該方法,用於實現子類自己的邏輯
- (Operation *)initWithNumebr1:(float)number1 number2:(float)number2;
@end
抽象運算類方法實現Operation.m (實現initWithNumebr1:number2:方法即可)
加法運算類Addition.h
#import "Operation.h"
// 繼承抽象運算類Operation
@interface Addition : Operation
@end
加法運算類方法實現Addition.m (重寫Operation類中的operate方法,實現加法邏輯即可)
客戶端main
#import <Foundation/Foundation.h>
#import "Calculate.h"
int main(int argc, const char * argv[]) {
@autoreleasepool {
// 將操作數1,操作數2,和操作符輸入到計算器中
// 操作符即加法類類名
NSLog(@"%.2f", [Calculate calculate:1 number2:2 operators:@"Addition"]);
}
return 0;
}
通過以上代碼,我們就成功實現了一個簡單工廠模式的計算器。下面將講解下OC的反射機制:
對於任意一個類,都能夠知道這個類的所有屬性和方法;對於任意一個對象,都能夠調用它的任意一個方法和屬性;這種動態獲取的信息以及動態調用對象的方法的功能稱為java語言的反射機制。
——百度百科 java反射
上面這句話是對java反射的介紹,我們也可以把它看做是OC反射的介紹。
例如上面的計算器程序,我們使用的是NSClassFromString方法來使用字符串獲得類。對於如何使用反射,獲得類中的方法、調用對象的方法、獲取對象屬於某個類等操作,我寫在了下面這篇文章中:
NSObject方法介紹
反射的好處還在於團隊合作時,如果對方負責的類並沒有完全實現,如果這時你引入肯定會報錯,那麼就可以用到反射。
--------------------------------------分割線 --------------------------------------
NSObject是OC中的基類,所有類都繼承於此,這裡面也給我們提供了很多與“類”和“方法”相關的方法,本文將講解幾個非常實用的方法。
環境信息:
Mac OS X 10.9
xcode 5.1.1
正文:
Person.h
#import <Foundation/Foundation.h>
@interface Person : NSObject
@end
Student.h
#import "Person.h"
// 繼承Person類
@interface Student : Person
- (void)test1;
- (void)test2:(NSString *)string;
@end
MyProtocol.h
#import <Foundation/Foundation.h>
@protocol MyProtocol
@end
1. 判斷student是否是Person類的對象
// - (BOOL)isMemberOfClass:(Class)aClass;
[student isMemberOfClass:[Person class]];
2. 判斷student是否是Person類或子類的對象
// - (BOOL)isKindOfClass:(Class)aClass;
[student isKindOfClass:[Person class]];
3. 判斷student是否遵循MyProtocol協議(也可以用類調用,判斷該類是否遵循)
// - (BOOL)conformsToProtocol:(Protocol *)aProtocol;
[student conformsToProtocol:@protocol(MyProtocol)];
// 或者使用類方法
// + (BOOL)conformsToProtocol:(Protocol *)protocol;
[Student conformsToProtocol:@protocol(MyProtocol)];
4. 判斷student的test1方法是否響應(即:是否聲明並實現了test1方法)
// - (BOOL)respondsToSelector:(SEL)aSelector;
[student respondsToSelector:@selector(test1)];
5. 間接調用student的test1方法(test1無參數)
// - (id)performSelector:(SEL)aSelector;
[student performSelector:@selector(test1)];
6. 間接調用student的test2方法(test2有一個參數)
// - (id)performSelector:(SEL)aSelector withObject:(id)object;
[student performSelector:@selector(test2:) withObject:@"123"];
// 最多帶兩個參數
//- (id)performSelector:(SEL)aSelector withObject:(id)object1 withObject:(id)object2;
7. 延遲2s調用student的test1方法
(在命令行沒有延遲效果,因為命令行執行完後就退出main函數了 ,在IOS部分main函數一直在執行,所以可以看到延遲效果)
// - (void)performSelector:(SEL)aSelector withObject:(id)anArgument afterDelay:(NSTimeInterval)delay;
// delay單位為(秒)
[student performSelector:@selector(test2:) withObject:@"123" afterDelay:2];