Reputation: 451
Wondering how people to design object and use of design pattern in a program.
For example:
Let's say I have two types of car ( BMW, Benz ) and two colors ( Black, White ), but the color object already exist with two methods which are
[Color initWithBlack];
[Color initWithWhite];
Define two methods in .h file
- (Car *)makeWithType:(NSString *)type;
- (Car *)makeWithType:(NSString *)type andColor:(NSString *)color;
In .m file
- (Car *)makeWithType:(NSString *)type
{
// default is black
return [self makeWithType:type andColor:@"black"];
}
- (Car *)makeWithType:(NSString *)type andColor:(NSString *)color
{
Car *car = [[Car alloc] init];
car.type = type;
switch(color) {
case "black":
[car addColor:[Color initWithBlack]];
break;
case "white":
[car addColor:[Color initWithWhile]];
break;
default:
break;
}
return car;
}
Is it the proper way to define and implement objects?
Are there any dependency coupling loose or tight?
If it is tight, how can I improve the design in order to reduce the coupling?
Upvotes: 1
Views: 245
Reputation: 25907
It seems to me a typical Factory pattern, where you have an object/class that creates objects for you. In this case I could call it CarsFactory
, and the methods could be class methods (+) and not instances ones (-), so:
+ (Car *)makeWithType:(NSString *)type;
+ (Car *)makeWithType:(NSString *)type andColor:(NSString *)color;
You can also have a look how Apple applies it, in their own classes. This is also an interesting article by Jon Reid.
Upvotes: 2
Reputation: 4725
Assuming the car types themselves add nothing to the car class, then what you have would be somewhat correct.
There are some flaws in there, first of all, the - (Car *)makeWithType:(NSString *)type;
method should probably be a class method and not an instance method. Having it be an instance method defeats the purpose of having it, as one would need to initialise a dummy car to then create the correct one through it.
Furthermore, if at some point you discover that BMWs can have properties that Benz's can't have, then subclassing would be more appropriate. Notice that you could still keep similar class method for creating cars, but in it, determine the correct subclass and return an instance of that class instead. This is what they call a class cluster. For example UIButton is a class cluster and takes in a type and returns a suitable concrete subclass for the given type.
Few more things, if you have constants, such as car makes or colours, then unless the colour object does something, then you would be better off using enums for these instead of strings and objects. There are a few advantages for that, first is clarity, right now there is no understanding of what types/colours are available when looking at the Car header file. With an enum you can immediately see the values that are available. Second is correctness, with strings it is easy to make mistakes and there is no checking by the compiler for correctness, with enums you'll get a big red alert if you've used a value that is not defined.
So as a conclusion, here's a header I would use for the class Car (assuming BMW and Benz are simply types and add no special meaning to a car)
typedef NS_ENUM(NSUInteger, CarMake) {
CarMakeBMW,
CarMakeBenz,
};
typedef NS_ENUM(NSUInteger, CarColor) {
CarColorBlack,
CarColorWhite,
};
@interface Car : NSObject
+ (Car *)makeWithType:(CarMake)make;
+ (Car *)makeWithType:(CarMake)make andColor:(CarColor)color;
@end
If you really need to use a Color object (btw, notice there is a typo in the initWithWhi(t)e
method name), then you should be passing in that colour to the method, and not a string referring to that colour. Alternatively use a mix of the header I have above and the colour objects, by creating a suitable object in the class method based on the enum value passed in.
Upvotes: 1