有效编码的最佳方法,因为它将被递归调用,并且创建大量对象是不好的。 +*-/, sin,cos,sqrt,pi and x,y,a,b
应该放在三个独立的if statements
中,不像现在一切都是分开的。同样为了可读性,制作包含 4 个isEqualToString
的 if 语句也不是很好。
NSString *operation = topOfStack;
if ([operation isEqualToString:@"+"]) {
} else if ([@"*" isEqualToString:operation]) {
} else if ([operation isEqualToString:@"-"]) {
} else if ([operation isEqualToString:@"/"]) {
} else if ([operation isEqualToString:@"sin"]) {
} else if ([operation isEqualToString:@"cos"]) {
} else if ([operation isEqualToString:@"sqrt"]) {
} else if ([operation isEqualToString:@"pi"]) {
} else if ([operation isEqualToString:@"x"]) {
} else if ([operation isEqualToString:@"y"]) {
} else if ([operation isEqualToString:@"a"]) {
} else if ([operation isEqualToString:@"b"]) {
}
相信有最好的方法可以做到这一点,但这里有另一种选择来补充已经给出的答案。
创建一个 NSDictionary,将您的操作名称(sin、sqrt、-)映射到选择器,如下所示:
NSDictionary *operations = @{
@"sin": [NSValue valueWithPointer:@selector(operationSin:)],
/* other operations here */
};
然后,您的 switch 语句将变为查找。
NSString *operation = topOfStack;
if(operations[operation]) {
SEL op = [operations[operation] pointerValue];
[self performSelector:op withObject:value]; /* Or some approximation thereof */
}
else {
/* Default action for unknown operation */
}
或者,您可以在已识别的操作上创建一个枚举,使用 NSDictionary 将操作名称映射到 NSNumber 装箱您的枚举值。
typedef NS_ENUM(NSUInteger, OperationType) {
OperationTypeSin = 0L,
OperationTypeSqrt,
/* and so on */
OperationTypeUnknown
};
/* And later... */
NSDictionary *operations = @{
@"sin": @(OperationTypeSin),
/* you get the idea */
};
/* Finally ... */
NSString *operation = topOfStack;
OperationType opType = [operations[operation] unsignedIntegerValue];
switch(opType) {
case OperationTypeSin:
/* Much cleaner, and type-safe too */
}
准备工作:
首先将 NSString 操作转换为 int 哈希代码,将该哈希代码存储在 #define或常量。
法典:
1) 将 NSString 操作转换为 int 哈希码 (tokenId)。
2) 然后在该令牌 ID 上执行一个开关语句。
int token = operationToToken(operation);
switch (token) {
case: OP_MINUS: break;
case: OP_SIN: break;
case: OP_COS: break;
}
首先,可以回退到 C 字符串,然后利用 sin
、cos
、sqrt
、pi
、a
、b
、x
和 y
(几乎)都以不同的字符开头的事实:
const char *s = [operation UTF8String];
switch (s[0]) {
case '+':
// addition
break;
case '-':
// subtraction
break;
case 's':
// sine or sqrt
switch (s[1]) {
case 'q':
// sqrt
break;
case 'i':
// sine
break;
}
break;
case 'c':
// cosine
break;
// et cetera...
default:
// not found
}
如果你使用的是Objective-C,那么你可以用一些名称巧妙的选择器来做到这一点。
首先,创建一个对象来封装Operation
。
然后,创建一个-initWithOperation:(NSString *)op
方法。在此方法中,将任何符号操作(*
、+
等)转换为唯一的字符串标识符(仅限字母)。
然后,您可以调用NSSelectorFromString(stringOp)
尽管如果您希望方法具有参数,则必须自己附加:
字符。
后,可以使用-performSelector:
、+performSelector:
执行选择器,或手动调用选择器。
如果您使用与操作相同的名称命名每个选择器,则不需要任何if
或switch
语句,但您必须处理发送无效选择器的情况。
例如:
@interface Operation : NSObject
- (id)initWithOperation:(NSString *)op;
- (void)performOperationWithValue:(float)value;
+ (float)sin:(float)value;
// ... Other operations
@property (nonatomic, copy) NSString *theOperation;
@end
@implementation Operation
- (id)initWithOperation(NSString *)op {
self = [super init];
if (self) {
// Convert symbols to unique strings
theOperation = [[NSString alloc] initWithString:op];
}
return self;
}
- (void)performOperationWithValue:(float)value {
NSString *withOneParam = [self.theOperation stringByAppendingString:@":"];
SEL sel = NSSelectorFromString(withOneParam);
[Operation performSelector:withOneParam withObject:[NSNumber numberWithFloat:value]];
}
// Class methods are the actual operation implementation...
在上面的示例中,我假设您已将@"sin"
传递给Operation
对象。这只能在Objective-C中实现,因为您可以利用命名选择器。
您可以为每个符号分配一个数字,并可以实现开关情况。