2
\$\begingroup\$

I am working on a product-related app where the data model for a product attribute feels too heavy. But I can't split it into several small data models because they are all about goods.

At present, my approach is to parse network data directly into a data model. The properties of the data model are readwrite. For example, when I want to modify a property, I will directly modify it, without copying or reinitializing the new data model. I know there may be problems with this, but I don't have a better way, if you have, please help me.

  • ATProductModel.h
#import "ATBaseModel.h"

NS_ASSUME_NONNULL_BEGIN

typedef NS_ENUM(NSUInteger, ATFilterType) {
    ATFilterTypeComplex = 0,
    ATFilterTypeSales,
    ATFilterTypePrice,
    ATFilterTypeVoucher,
};

typedef NS_ENUM(NSUInteger, ATFilterLayoutType) {
    ATFilterLayoutTypeNone = 0,
    ATFilterLayoutTypeOneRows, 
    ATFilterLayoutTypeMoreRows, 
};

@interface ATProductSubModel : ATBaseModel

@property (copy, nonatomic) NSString *productId;
@property (copy, nonatomic) NSString *productURL;
@property (copy, nonatomic) NSString *productURLShort;
@property (copy, nonatomic) NSString *productIcon;
@property (copy, nonatomic) NSString *title;
@property (copy, nonatomic) NSString *voucher;
@property (copy, nonatomic) NSString *currentPrice;
@property (copy, nonatomic) NSString *price;
@property (copy, nonatomic) NSString *couponURL;
@property (copy, nonatomic) NSString *discountRate;
@property (copy, nonatomic) NSString *endTime;
@property (copy, nonatomic) NSString *couponInfo;
@property (copy, nonatomic) NSString *volume;
@property (copy, nonatomic) NSString *couponStartTime;
@property (copy, nonatomic) NSString *couponEndTime;
@property (copy, nonatomic) NSArray <NSString *>* smallImages;
@property (copy, nonatomic) NSString *shopName;
@property (copy, nonatomic) NSString *shopLogo;
@property (copy, nonatomic) NSString *platType;
@property (copy, nonatomic) NSString *shopScore;
@property (copy, nonatomic) NSString *share;
@property (copy, nonatomic) NSString *shareFee;
@property (copy, nonatomic) NSString *income;
@property (copy, nonatomic) NSString *upIncome;
@property (strong, nonatomic) NSNumber *finished;

+ (instancetype)defaultModel;

@end

@interface ATProductModel : ATBaseModel

@property (strong, nonatomic) NSArray <ATProductSubModel *>* products;
@property (assign, nonatomic) ATFilterLayoutType layoutType;
@property (assign, nonatomic) BOOL recommended;

@end

NS_ASSUME_NONNULL_END

  • ATProductViewController.h
#import "ATProductModel.h"

NS_ASSUME_NONNULL_BEGIN

@interface ATProductViewController : UIViewController

@property (strong, nonatomic) ATProductSubModel *model;

@end

  • ATProductViewController.m
#import "ATStringUtil.h"

@implementation ATProductViewController

@property (strong, nonatomic) ATProductModel *productModel;

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    [self defaultModels];
}

- (void)defaultModels{

    NSMutableArray *smallImages = [NSMutableArray arrayWithArray:self.model.smallImages];
    if (![ATStringUtil containStr:self.model.icon inArr:self.model.smallImages]) {
        [smallImages insertObject:self.model.icon atIndex:0];
    }
    self.model.smallImages = smallImages;
}

@end
```
\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

In terms of number of properties, I wouldn’t worry about that. There are situations where you can have lots of properties. As the philosopher says, “it is what it is.”

Obviously, from a data modeling perspective, what doesn’t feel quite right is to combine product info, coupon info, shop info, etc. into a single object. E.g. products sometimes are eligible for multiple coupons. Or perhaps you’ll be repeating the “shop” information multiple times in your result set.

That having been said, it depends upon what this feed is for: If this is a search result employed within a particular view within the app, then perhaps a fairly flat structure, like yours, is fine (though I might call the object a “search result” rather than a “product”). But if this is for populating a local data store that users can search locally, then I might expect separate objects for the different entity types (a product object, a shop object, etc.). I’d ask myself how often can the same information be repeated in a particular result set. But whether you have a denormalized/flat result set, or a more normalized product database, just depends upon the nature of the API and how this is being used within the app.

The only change that really jumps out at me is that there are several properties that would appear to be numeric types that are captured as strings (e.g. prices, rates, fees, income, etc.). Perhaps your feed returns them as strings, but within your app, you don’t want to have to sprinkle your code with string-to-number conversions so that you can do things like show the user grand totals, convert rates to totals, or the like. I might be inclined to do that string-to-number conversion while parsing the feed (or, better, change the feed to actually return numeric types) and then I’m working purely with numeric types within the app.

\$\endgroup\$
3
  • \$\begingroup\$ Thank you very much for your answer. According to your suggestion, some attributes can also be packaged into new classes. Some attributes need to be modified to a numeric type. I have been learning refactoring recently, and controlling variable values is very final. I plan to add an initialization method, all public properties are changed to read-only, and an update method is provided for the properties that need to be modified. I have two problems, the first initialization method is too long, the second one if too many properties need to provide an update method \$\endgroup\$
    – Nullable
    Sep 4, 2019 at 2:33
  • \$\begingroup\$ Out of curiosity, why do your properties need update methods vs just enjoying the synthesized setters? \$\endgroup\$
    – Rob
    Sep 4, 2019 at 5:28
  • \$\begingroup\$ The property is readable and writable by default, meaning it can be changed anywhere, which is dangerous for the property being used. So modify the property to read-only, but sometimes you need to update the property value, this time I want to provide an updated method. This seems to be the same as the default readable and writable, I also feel a bit strange \$\endgroup\$
    – Nullable
    Sep 4, 2019 at 6:46

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.