Что такое switch и как с ним бороться?

от автора

Программа без ветвления — очень простая и странная программа. Программа должна думать, просчитывать варианты, по-разному реагировать на различные внешние воздействия и вообще не быть однообразной. А это все невозможно без ветвлений. Ветвления реализуются при помощи опреаторов if и switch. Так зачем е с ним бороься?

Периодически, при просмотре чужого кода, мне попадаются длинные методы и громоздкие конструкции вложенных 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/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *