Периодически, при просмотре чужого кода, мне попадаются длинные методы и громоздкие конструкции вложенных if и switch. Например, такие:
// Примеры кода приведены на Objective C, но без проблем могут быть перенесены на другой язык программирования - (NSUInteger)numberOfItemsInSection:(NSUInteger)section { if (self.loggedIn) { swtich (section) { case 0: return 2; case 1: { if (self.settings.showDetails) { return 5; } else { return 3; } } case 2: return 3; } } else { swtich (section) { case 1: { if (self.settings.showDetails) { return 5; } else { return 3; } } case 2: return 3; } } }
Меня лично, такие методы пугают и они просто не помещяются в моей голове. Первое что просится — это дать названия всем магичесским числам. Например, так:
enum SectionIndex { LoginSection = 0, DetailsSection, ExtendedSection }
Но если присмотреться, то мы не учитываем LoginSection если установлено значение self.loggedIn и прячем DetailsSection если сброшено значение self.settings.showDetails. Но мы просто преобразуем значение section в SectionIndex исходя из текущего состояния:
- (SectionIndex)sectionIndexForSection:(NSUInteger)section { if (!self.loggedIn) { ++section; } if (!self.settings.showDetails) { ++section; } return (SectionIndex)section; } - (NSUInteger)numberOfItemsInSection:(NSUInteger)section { SectionIndex sectionIndex = [self sectionIndexForSection:section]; switch (sectionIndex) { case LoginSection: return [self numberOfItemsInLoggedInSection]; case DetailsSection: return [self numberOfItemsInDetailsSection]; case ExtendedSection: return [self numberOfItemsInExtendedSection] } } }
По-моему, уже выглядит гораздо приятнее, особенно если учесть, что таких ветвлений в объекте обычно несколько. Например, -titleForItem:inSection:, -performActionForItem:inSection: и т.п. А что если вспомнить о том, что язык у нас объектно-ориентированный, и состояние системы можно занести в объект-состояние? Тогда все эти методы сократятся до одной строки — обращение к объекту-состояния?
- (NSUInteger)numberOfSections { retun [self.state numberOfSections]; } - (NSUInteger)numberOfItemsInSection:(NSUInteger)section { retun [self.state numberOfItemsInSection:section]; } - (NSString *)titleForItem:(NSUInteger)item inSection:(NSUInteger)section { retun [self.state titleForItem:item inSection:section]; } - (void)performActionForItem:(NSUInteger)item inSection:(NSUInteger)section { retun [self.state performActionForItem:item inSection:section]; }
По-моему, вполне красиво. Осталось только откуда-то досать это самое состояние. Можн настраивать объекты состояний в самом объекте или написать нескольуо классов, определяющих состояния.
@interface State : NSObject @property (nonatomic, strong) NSDictionary *sections; // ... @end @implementation State - (NSUInteger)numberOfSections { return [self.sections count]; } - (NSUInteger)numberOfItemsInSection:(NSUInteger)section { return [self.sections[section] count]; } - (NSString *)titleForItem:(NSUInteger)item inSection:(NSUInteger)section { return self.sections[section][item][@"title"]; } - (void)performActionForItem:(NSUInteger)item inSection:(NSUInteger)section { void(^actionBlock)() = self.sections[section][item][@"action"]; actionBlock(); } // Настройка состояний - (void)setupForState { NSMutableDictionary *state = [NSMutableDictionary dictionary]; if (self.loggedIn) { [state addObject:[self loggedInSection]]; } if (self.showDetails) { [state addObject:[self detailsSection]]; } [state addObject:[self extendedSection]]; self.sections = state; } - (NSArray *)loggedInSection {...} - (NSArray *)detailsSection {...} - (NSArray *)extendedSection {...} // ...
Получается, что мы избавились от ветвлений в нескольких местах, заменив его одной установкой состояния, а сами состояния получились целостными, понятными и собранными в одном месте.
ссылка на оригинал статьи http://habrahabr.ru/post/218119/
Добавить комментарий