Search code examples
iosobjective-cfactory-pattern

iOS: Using the Factory Design Pattern to Dynamically Change Accessible Properties?


I have the following example where CarTypeTesla is an enum value.

Car *car = [Car carOfType:CarTypeTesla];

+ (instanceType)carOfType: does an enum check and returns an instance of a given Car subclass, like this:

+ (instanceType)carOfType:(CarType)carType {

    switch (carType) {
        case: CarTypeTesla: {

            return [[Tesla alloc] init];
        }

        case: CarTypeMustang: {

            return [[Mustang alloc] init];
        }
    }
}

So that back in the main file something like this can be done (And I don't have to expose my Tesla, Mustang, and 20 other subclasses):

Car *car = [Car carOfType:CarTypeTesla];
NSLog(@"%@", car.batteryChargeRemaining);

or

Car *car = [Car carOfType:CarTypeMustang];
NSLog(@"%@", car.gasFuelRemaining);

How can I use this Factory Design Pattern, to only display properties / methods related to the returned subclass based on the enum value provided (Wouldn't want to show -(float)gasFuelRemaining when using CarTypeTesla?


Solution

  • What you are implementing is known as a class cluster in iOS. Some framework classes, like NSArray, NSString and NSDictionary work like this (they optimise by providing different solutions based on the amount of data they hold). This allows you to have a generic, common class that's exposed to the API, while hiding all the intricate details for solutions that are not necessarily relevant for developers, including solutions that are different based on context but should behave the same. What this means is you have a generic base class with common methods that are implemented across all other hidden classes.

    The way I see it you have to options: 1 - You implement all methods in all your car classes, and have them return empty values when they are not relevant, in which case your Tesla instances would return 0 for gasFuelRemaining OR 2 - You implement protocols for different types of cars, like ElectricCarProtocol and FuelCarProtocol and have a common method in your Car class called fuelRemaining that does something along the lines of this:

    if ([self conformsToProtocol:@protocol(ElectricCarProtocol)]) {
        return self.batteryChargeRemaining; // you might need to cast the object here
    }
    return self.gasFuelRemaining; // idem
    

    Hope this helps!