MST

星途 面试题库

面试题:Objective-C 工厂模式在复杂项目中的应用与优化

在一个大型Objective-C项目中,需要频繁创建多种类型的网络请求对象,每种请求对象都有不同的初始化参数和配置。请描述如何运用工厂模式来管理这些对象的创建,同时考虑如何优化代码结构以提高可维护性和可扩展性,例如如何处理对象创建过程中的错误处理与资源管理。
12.2万 热度难度
编程语言Objective-C

知识考点

AI 面试

面试题答案

一键面试
  1. 定义网络请求基类

    • 创建一个基类,例如NetworkRequest,作为所有网络请求对象的基类。它可以包含一些通用的属性和方法,如请求的URL、请求方法(GET、POST等)、请求头、以及发送请求和处理响应的通用逻辑。
    @interface NetworkRequest : NSObject
    @property (nonatomic, strong) NSURL *url;
    @property (nonatomic, strong) NSString *requestMethod;
    @property (nonatomic, strong) NSDictionary<NSString *, NSString *> *headers;
    - (void)sendRequestWithCompletion:(void (^)(NSData * _Nullable data, NSError * _Nullable error))completion;
    @end
    
    @implementation NetworkRequest
    - (void)sendRequestWithCompletion:(void (^)(NSData * _Nullable data, NSError * _Nullable error))completion {
        NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url];
        request.HTTPMethod = self.requestMethod;
        [self.headers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
            [request setValue:obj forHTTPHeaderField:key];
        }];
        NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
            completion(data, error);
        }];
        [task resume];
    }
    @end
    
  2. 定义具体的网络请求子类

    • 根据不同类型的网络请求,创建继承自NetworkRequest的子类。例如,假设我们有登录请求和获取用户信息请求。
    @interface LoginRequest : NetworkRequest
    - (instancetype)initWithUsername:(NSString *)username password:(NSString *)password;
    @end
    
    @implementation LoginRequest
    - (instancetype)initWithUsername:(NSString *)username password:(NSString *)password {
        self = [super init];
        if (self) {
            self.url = [NSURL URLWithString:@"https://example.com/login"];
            self.requestMethod = @"POST";
            NSMutableDictionary<NSString *, NSString *> *body = [NSMutableDictionary dictionary];
            body[@"username"] = username;
            body[@"password"] = password;
            NSString *bodyString = [body queryString];// 假设这里有一个将字典转成query string的category方法
            self.headers = @{@"Content-Type": @"application/x-www-form-urlencoded", @"Content-Length": @(bodyString.length).stringValue};
            [self setValue:bodyString forHTTPBody:[bodyString dataUsingEncoding:NSUTF8StringEncoding]];
        }
        return self;
    }
    @end
    
    @interface UserInfoRequest : NetworkRequest
    - (instancetype)initWithUserId:(NSString *)userId;
    @end
    
    @implementation UserInfoRequest
    - (instancetype)initWithUserId:(NSString *)userId {
        self = [super init];
        if (self) {
            self.url = [NSURL URLWithString:[NSString stringWithFormat:@"https://example.com/user/%@", userId]];
            self.requestMethod = @"GET";
            self.headers = @{@"Content-Type": @"application/json"};
        }
        return self;
    }
    @end
    
  3. 创建工厂类

    • 创建一个工厂类,例如NetworkRequestFactory,用于创建不同类型的网络请求对象。
    @interface NetworkRequestFactory : NSObject
    + (NetworkRequest *)createRequestWithType:(NSString *)type parameters:(NSDictionary *)parameters;
    @end
    
    @implementation NetworkRequestFactory
    + (NetworkRequest *)createRequestWithType:(NSString *)type parameters:(NSDictionary *)parameters {
        if ([type isEqualToString:@"login"]) {
            NSString *username = parameters[@"username"];
            NSString *password = parameters[@"password"];
            return [[LoginRequest alloc] initWithUsername:username password:password];
        } else if ([type isEqualToString:@"userInfo"]) {
            NSString *userId = parameters[@"userId"];
            return [[UserInfoRequest alloc] initWithUserId:userId];
        }
        return nil;
    }
    @end
    
  4. 错误处理与资源管理

    • 错误处理
      • NetworkRequest基类的sendRequestWithCompletion方法中,当网络请求失败时,通过completion block返回NSError对象,告知调用者错误信息。例如:
      - (void)sendRequestWithCompletion:(void (^)(NSData * _Nullable data, NSError * _Nullable error))completion {
          NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:self.url];
          request.HTTPMethod = self.requestMethod;
          [self.headers enumerateKeysAndObjectsUsingBlock:^(NSString * _Nonnull key, NSString * _Nonnull obj, BOOL * _Nonnull stop) {
              [request setValue:obj forHTTPHeaderField:key];
          }];
          NSURLSessionDataTask *task = [[NSURLSession sharedSession] dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
              if (error) {
                  completion(nil, error);
              } else {
                  // 还可以在这里根据HTTP状态码进行更细粒度的错误处理
                  NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                  if (httpResponse.statusCode >= 400) {
                      NSError *customError = [NSError errorWithDomain:@"NetworkErrorDomain" code:httpResponse.statusCode userInfo:nil];
                      completion(nil, customError);
                  } else {
                      completion(data, nil);
                  }
              }
          }];
          [task resume];
      }
      
    • 资源管理
      • 在网络请求对象创建过程中,尽量避免内存泄漏。例如,在NetworkRequest子类的初始化方法中,正确设置属性和初始化资源,并且在对象销毁时(如果有需要手动释放的资源),在dealloc方法中释放资源。对于NSURLSessionDataTask,当任务完成(成功或失败),系统会自动管理其相关资源,一般不需要额外手动释放。
  5. 优化代码结构提高可维护性和可扩展性

    • 可维护性
      • 将网络请求相关的代码集中在NetworkRequest基类和其具体子类以及NetworkRequestFactory中,使得代码结构清晰,易于理解和维护。如果需要修改网络请求的通用逻辑,只需要在NetworkRequest基类中修改;如果需要修改某一种具体请求的逻辑,只需要在对应的子类中修改。
    • 可扩展性
      • 当需要添加新的网络请求类型时,只需要创建新的继承自NetworkRequest的子类,并在NetworkRequestFactorycreateRequestWithType:parameters:方法中添加相应的创建逻辑即可,不需要对现有的其他请求类和工厂类的主要逻辑进行大规模修改。同时,如果需要对网络请求添加新的通用功能,如添加请求超时处理,只需要在NetworkRequest基类中添加相关逻辑,所有子类都会继承该功能。