What to do with inherited factory methods?

Suppose I have a BasicDate class and a subclass of BasicDate called EuroDate . The difference between the classes is month-day-year and day-month-year. I know that it would probably be better to just use the methods of one class to output them differently ... but that is not the question of this question.

BasicDate has the following init method :

 -(id)initWithMonth:(int)m andDay:(int)d andYear:(int)y { if(self = [super init]) { /*initialize*/ } return self; } 

And the corresponding factory method as follows:

 +(BasicDate)dateWithMonth:(int)m andDay:(int)d andYear:(int)y { return [[BasicDate alloc] initWithMonth: m andDay: d andYear: y]; } 

But if my EuroDate subclass, which will use the factory method , looks more like this:

 +(EuroDate)dateWithDay:(int)d andMonth:(int)m andYear:(int)y { return [[EuroDate alloc] initWithDay: d andMonth: m andYear: y]; } //we can assume that EuroDate includes this init method... 

Everything is good. Suppose both classes have their own description method , which prints MMDDYYYY for BasicDate , but DDMMYYYY with EuroDate . This is still good.

But if I do this:

 EuroDate today = [EuroDate dateWithMonth:10 andDay:18 andYear:2013]; 

This will invoke the BasicDate factory method that BasicDate inherited. The problem is, remember what the BasicDate factory method looks like? return [[BasicDate alloc] ...]

So, today polymorphic in BasicDate , although I want to save it as EuroDate , so if I call the description method, it will print 10182013 , not 18102013 .

There are two solutions to this problem that I have found.

Solution 1: change the BasicDate factory method. Instead of return [[BasicDate alloc] ... I can instead execute return [[[self class] alloc] ...] This works and allows me to use this method for BasicDate or any of the BasicDate subclasses, and it will return the correct object type .

Solution 2: Override factory method. Regardless of whether I redefine it to exclude or redefine it to execute return [[EuroDate alloc] ...] . The problem with overriding is that I have to override each factory method for each subclass.

What's better? What are some of the disadvantages for two possible solutions that might be missing? What is considered the standard way to solve this problem in Objective-C?

+2
source share
1 answer

Normally, you should use the [[[self class] alloc] init...] methods in the factory to ensure that they instantiate the correct class. Note that class not a property (and in fact there is no such thing as a โ€œclass propertyโ€), so using dot syntax is inappropriate.

Edit

And as @ArkadiuszHolko (and Rob, thank you) pointed out, now you should use instancetype instead of id for the return value in order to get the benefits of strong typing, while maintaining type flexibility for subclasses. And by the way, Apple's naming conventions suggest avoiding the use of the word "and" in method names. Therefore, consider rewriting your convenience method like this:

 + (instancetype)dateWithMonth:(int)month day:(int)day year:(int)year { return [[self alloc] initWithMonth:month day:day year:year]; } 
+3
source

Source: https://habr.com/ru/post/957857/


All Articles