Wzorce projektowe: Budowniczy (Builder) w Objective-C

Budowniczy (ang. Builder) to wzorzec pomagający nam w tworzeniu skomplikowanych obiektów. Poprzednio pokazałem implementację w Swift. Dziś jest kolaj na kod w Objective-C.

Opis wzorcahttp://pl.wikipedia.org/wiki/Budowniczy_(wzorzec_projektowy)

Ponownie jak w przypadku Budowniczego w Swift, użyję przykładu z tworzeniem MacBooka. Zdefiniujmy sobie protokół, który pokażę nam zakres konfiguracji.

@protocol MacBuilder
 
-(void) setStandardDisplay;
-(void) setRetinaDisplay;
 
-(void) set11Inches;
-(void) set13Inches;
-(void) set15Inches;
 
-(void) setSSD;
-(void) setHDD;
-(void) setSSDandHDD;
 
-(void) seti5;
-(void) seti7;
 
-(MacBook*) getResult;
 
@end

Skoro wiemy już jakie mamy opcje, to wypadałoby stworzyć klasę MacBook, która zamodeluje nam rzeczywisty obiekt.

@interface MacBook : NSObject
 
@property (nonatomic) ScreenSize screenSize;
@property (nonatomic) DisplayType displayType;
@property (nonatomic) StorageType storageType;
@property (nonatomic) CPUType cpuType;
 
-(MacBook*)initWithDisplayType:(DisplayType)displayType withScreenSize:(ScreenSize)screenSize withStorageType:(StorageType)storageType withCpuType:(CPUType)cpuType;
 
@end

Opcje konfiguracji warto jest wydzielić tak jak ja powyżej, do odpowiednich, dedykowanych typów danych. W ten sposób zamkniemy drogę do potencjalnych błędów w bezsensownych konfiguracjach MacBooka, np ekran o wielkości 100 cali lub możliwość wsadzenia procesora AMD w ten komputer.

typedef enum : NSUInteger {
 SSD,
 HDD,
 SSD_HDD
} StorageType;
 
typedef enum : NSUInteger {
 Standard,
 Retina
} DisplayType;
 
typedef enum : NSUInteger {
 i5,
 i7,
} CPUType;
 
typedef enum : NSUInteger {
 s11inch,
 s13inch,
 s15inch,
} ScreenSize;

Teraz pora na Budowniczego:

#import <Foundation/Foundation.h>
#import "MacBuilder.h"
 
@interface MacBookBuilder : NSObject <MacBuilder>
 
@end

Czyli tworzymy sobie klasę, która implementuje zdefiniowany poprzednio protokół. Implementacja tej klasy może wyglądać na przykład tak

#import "MacBookBuilder.h"
 
@implementation MacBookBuilder {
 StorageType storageType;
 DisplayType displayType;
 CPUType cpuType;
 ScreenSize screenSize;
}
 
-(void) setStandardDisplay {
 displayType = Standard;
}
 
-(void) setRetinaDisplay {
 displayType = Retina;
}
 
-(void) set11Inches {
 screenSize = s11inch;
}
 
-(void) set13Inches {
 screenSize = s13inch;
}
 
-(void) set15Inches {
 screenSize = s15inch;
}
 
-(void) setSSD {
 storageType = SSD;
}
 
-(void) setHDD {
 storageType = HDD;
}
 
-(void) setSSDandHDD {
 storageType = SSD_HDD;
}
 
-(void) seti5 {
 cpuType = i5;
}
 
-(void) seti7 {
 cpuType = i7;
}
 
-(MacBook*) getResult {
 MacBook* mb = [[MacBook alloc] initWithDisplayType: displayType withScreenSize: screenSize withStorageType: storageType withCpuType: cpuType];
 return mb;
}
 
@end

Następnie kolej na sprawdzenie, czy to rzeczywiście jest poprawne. W pliku BuilderTests.m dodajemy 3 przypadki testowe:

- (void)testBuildMacBookAir {
 MacBookBuilder* mbb = [[MacBookBuilder alloc] init];
 [mbb set11Inches];
 [mbb setStandardDisplay];
 [mbb setSSD];
 [mbb seti5];
 MacBook* mb = [mbb getResult];
 
 XCTAssertEqual(mb.cpuType, i5, @"CPU Incorrect");
 XCTAssertEqual(mb.storageType, SSD, @"Storage Incorrect");
 XCTAssertEqual(mb.displayType, Standard, @"Display Incorrect");
 XCTAssertEqual(mb.screenSize, s11inch, @"Screen Size Incorrect");
}
 
- (void)testBuildMacBookProRetina {
 MacBookBuilder* mbb = [[MacBookBuilder alloc] init];
 [mbb set15Inches];
 [mbb setRetinaDisplay];
 [mbb setSSD];
 [mbb seti7];
 MacBook* mb = [mbb getResult];
 
 XCTAssertEqual(mb.cpuType, i7, @"CPU Incorrect");
 XCTAssertEqual(mb.storageType, SSD, @"Storage Incorrect");
 XCTAssertEqual(mb.displayType, Retina, @"Display Incorrect");
 XCTAssertEqual(mb.screenSize, s15inch, @"Screen Size Incorrect");
}
 
- (void)testBuildMacBookPro {
 MacBookBuilder* mbb = [[MacBookBuilder alloc] init];
 [mbb set13Inches];
 [mbb setStandardDisplay];
 [mbb setHDD];
 [mbb seti5];
 MacBook* mb = [mbb getResult];
 
 XCTAssertEqual(mb.cpuType, i5, @"CPU Incorrect");
 XCTAssertEqual(mb.storageType, HDD, @"Storage Incorrect");
 XCTAssertEqual(mb.displayType, Standard, @"Display Incorrect");
 XCTAssertEqual(mb.screenSize, s13inch, @"Screen Size Incorrect");
}

Rezultat testów będzie jak na obrazku poniżej:

Builder Test Result

Budowniczy w Objective-C działa jak widać poprawnie.

 


Projekt Xcode i pliki źródłowe z przykładowym kodem można znaleźć tutaj.


Ten post jest częścią cyklu o wzorcach projektowych w Objective-C i Swift. Strona Wzorce projektowe w Objective-C i Swift – Kompendium  zbiera w jednym miejscu wzorce i przypisane do nich artykuły. Zapraszam do lektury.

Dodaj komentarz