Concise Gold Challenge Solution


#1

I looked through some examples of solutions for the Gold Challenge and saw many with complicated and long solutions to work around the issue of BNRContainer objects possibly containing other BNRContainers objects. Rather than write additional initializers and overrides … I simply subclassed BNRContainer to have only two additional instance variables: (1) a totalValue that would sum the container value plus the value of contained objects and (2) a subItems NSMutableArray. The only methods I needed to write were: (1) a method to add a BNRItem (or BNRContainer) to the container and (2) a read-only instance variable for totalValue that sums the container value and the BNRItems (or BNRContainers) within.

Here is the simple header file for BNRContainer:

#import "BNRItem.h"

@interface BNRContainer : BNRItem
{
    NSMutableArray *subitems;
    int totalValue;
}

// Read only instance variable that is calculated based upon
// valueInDollars of container and value of items
- (int)totalValue;

- (void)addBNRItem:(BNRItem *)item;

@end

Here is the implementation file for BNRContainer:

#import "BNRContainer.h"

@implementation BNRContainer

// Override of BNRItem description method that is specific for a BNRContainer

- (NSString *)description
{
    NSMutableString *descriptionString = [NSMutableString stringWithFormat:@"Container Name: %@  Total Value: $%d  Items:\n",
                                          self.itemName, self.totalValue];
    for (BNRItem *item in subitems) {
        [descriptionString appendFormat:@"     %@\n", item];
    }
    return descriptionString;
}

// Instance method to read total value

- (int)totalValue
{
    int sumOfValues = 0;
    
    // First obtain value of container
    sumOfValues = self.valueInDollars;
    
    // Next add value of each item in container
    for (BNRItem *item in subitems) {
        
        // If the item is another BNRContainer, need to add totalValue
        // If the item is a BNRItem, need to just add valueInDollars
        if ([item isKindOfClass:[BNRContainer class]]) {
            BNRContainer *containerItem = (BNRContainer *)item;
            sumOfValues += containerItem.totalValue;
        } else {
            sumOfValues += item.valueInDollars;
        }
    }
    return sumOfValues;
}

// Other methods

- (void)addBNRItem:(BNRItem *)item
{
    // If adding the first item to the container, need to create the NSMutableArray to hold the contained items
    if (!subitems) {
        subitems = [[NSMutableArray alloc] init];
    }
    [subitems addObject:item];
}

@end

Overriding the description method was pretty straightforward and utilized the new instance variable totalValue. The method to add an item to the container was pretty straight forward and by testing to see if the NSMutableArrray items existed, this gave me an easy way to create the NSMutableArrray if it did not yet exist (instead of overriding initialization methods). The only slightly complication was the read only method that returned totalValue. This had to add in the value of the container (an inherited value from BNRItem) but then had to add it the value of each item contained in the subItems array. To handle the possibility of containers being within containers, the code has to check for the type of object for each item. If it finds a simple BNRItem then it simply adds the valueInDollars. If it finds it to be a BNRContainer, then the BNRItem is casted to a BNRContainer and the totalValue is used.

Below is my test code in main that does verify this works with using containers within containers:

#import <Foundation/Foundation.h>
#import "BNRItem.h"
#import "BNRContainer.h"

int main(int argc, const char * argv[])
{

    @autoreleasepool {
        
        // Create a mutable array
        NSMutableArray *items = [[NSMutableArray alloc] init];
        
        // Create 10 BNRItems
        for (int i = 0; i < 10; i++) {
            BNRItem *item = [BNRItem randomItem];
            [items addObject:item];
        }
                
        // Log objects in items arrray
        for (BNRItem *item in items) {
            NSLog(@"%@", item);
        }
        
        // Create a container object
        BNRContainer *container = [[BNRContainer alloc] initWithItemName:@"Big Box" valueInDollars:10 serialNumber:@"ZZZZZ"];
        
        // Add first three items from items array into container object
        [container addBNRItem:items[0]];
        [container addBNRItem:items[1]];
        [container addBNRItem:items[2]];
        
        // Log the container
        NSLog(@"%@", container);
        
        // Create a second container object
        BNRContainer *secondContainer = [[BNRContainer alloc] initWithItemName:@"Bigger Box" valueInDollars:20 serialNumber:@"YYYYY"];
        
        // Add first container and the last item from items array into the second container
        [secondContainer addBNRItem:container];
        [secondContainer addBNRItem:items[9]];
         
         // Log the second container
         NSLog(@"%@", secondContainer);
        
        // Destroy the array
        items = nil;
    }
    return 0;
}