I have gone through couple of video and blog tuts online. Felt like i understood everything, however still struggling to implement the Abstract factory pattern. Here is my requirement:
I have a User class which should give a user object.
There are two types of users in my application for e.g Service Provider (Provider) and Service receiver (Consumer).
There are some common properties between these two types of users like name, email id , mobile number etc. For Provider type there will be some extra properties.
Provider types could be of for e.g. TaxiDriver or Restaurant etc.
I want to implement Abstract factory and factory method pattern for this user class so that the application can be decoupled from the User model and whenever the application wants an User of type Provider or Consumer it should get the right object.
What I tried so far:
AbstracUserProtocol.h
#protocol AbstractUserProtocol
#required
#property(nonatomic, strong) id delegate;
#property(nonatomic, readonly, getter=isExist) BOOL exist;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailID;
#property (nonatomic, assign) NSInteger phoneNumber;
-(void)saveUserData;
-(void)retrievUserData;
#end
AbstractUser.h
#interface AbstractUser : NSObject <AbstractUserProtocol>
-(id)initWithType:(UserType)usrType;
#end
AbstractUser.m
#implementation AbstractUser
#synthesize delegate, exist, name, emailID, phoneNumber;
-(id)initWithType:(UserType)usrType
{
self = nil;
if (usrType == kConsumer) {
self = [Consumer alloc]init];
}
else if (usrType == kProvider) {
self = [ProviderFactory alloc] initWithServiceType:TaxiService];
}
return self;
}
-(void)saveUserData {
[NSException raise:NSInternalInconsistencyException
format:#"You have not implemented %# in %#",
NSStringFromSelector(_cmd), NSStringFromClass([self class])];
}
-(void)retrievUserData {
}
#end
Now created two subclasses Consumer and ProviderFactory from AbstractUser class.
Consumer.h
#interface Consumer : AbstractUser
#property (nonatomic, strong) NSString *address;
#end
ProviderFactory.h
#interface ProviderFactory : AbstractUser
-(id)initWithServiceType:(ServiceType)srvType;
#property(nonatomic, strong) NSString *ownerDetails;
#end
So whenever in future if my application want to support another business user like Taxi and Restaurant type then I just have to create a class and init through ProviderFactory class.
Is my approach correct for the abstract Factory pattern? Appreciate any guidance.
Based on your follow up question, I edited the answer.
I'm not entirely sure you need to use AbstractFactory for what you are trying to accomplish. The basics of AbstractFactory is that it allows you to
provide an interface for creating families of related or dependent
objects without specifying their concrete classes (Gamma et al.)
Take this example from Design Patterns: Elements of Reusable Object-Oriented Software by Gamma et al. Let's say you are creating a toolkit to build user interfaces for a document editor. You may have a bunch of widget objects like scrollers, buttons, toolbars, etc. But you may want to later add a different look-and-feel to the document editor. So then you can use AbstractFactory to provide an interface to create all of the widget products (i.e. createScrollbar, createButtons, etc.) but then to change the look-and-feel, you subclass the abstract class and override the methods so that say, createScrollbar returns a scrollbar that has a 3-D effect. In another case, you subclass the abstract class to create a pink scrollbar. The options are endless, and since your client code doesn't care what the scrollbar looks like (all the client cares about is whether it scrolls text or not), you can easily add future looks-and-feels without touching the client code.
In your case, the client cares what kind of AbstractUser it is getting because in some cases it needs a Customer and in some cases a Provider. So either way, your client code would have to be changed if in the future you added a new kind of user.
That said, I think the best approach for you would be to just create an abstract base class of User and then subclass it and add the user-specific properties to the subclass. Here is an example of what I mean.
AbstractUser.h
#import <Foundation/Foundation.h>
#interface AbstractUser : NSObject
#property(nonatomic, strong) id delegate;
#property(nonatomic, readonly, getter=isExist) BOOL exist;
#property (nonatomic, strong) NSString *name;
#property (nonatomic, strong) NSString *emailID;
#property (nonatomic, assign) NSInteger phoneNumber;
#end
Consumer.h
#import "AbstractUser.h"
#interface Consumer : AbstractUser
#property (strong, nonatomic) NSString *address;
#end
ViewController.m
#import "ViewController.h"
#import "Consumer.h"
#import "Provider.h"
#interface ViewController ()
#property (strong, nonatomic) Consumer *consumer;
#property (strong, nonatomic) Provider *provider;
#end
#implementation ViewController
- (void)viewDidLoad
{
[super viewDidLoad];
_consumer = [[Consumer alloc] init];
_provider = [[Provider alloc] init];
self.consumer.name = #"Jason";
self.consumer.address = #"some address";
self.provider.name = #"Stack Overflow";
#end
Related
i successfully integrated core data in my JSQ project, for my JSQMessageData i use NSManagedObject i created called CDChatMessage
#interface CDChatMessage : NSManagedObject < JSQMessageData >
#end
at my JSQMessagesViewController i use NSfetchedresultsController,
it works fine for text messages but i can't figure out how to implement media messages.
JSQMessage.h have a property that represent the Media Data
#property (copy, nonatomic, readonly) id< JSQMessageMediaData > media;
but obviously i cant assassin property of type JSQMessageMediaData to my NSManagedObject,
anyone have a solution for using JSQMessageMediaData with Core Data ?
thanks.
Basically what I've done to solve this kind of issue is this:
Instead of using CoreData object which conforms to JSQMessageData I use something called viewModel.
A ViewModel is basically a normal NSObject which just unwraps all necessary information from the CoreData object and conforms to JSQMessageData protocol - providing text, senderId, and other information (and also media message if necessary)
#interface ChatMessageViewModel : NSObject <JSQMessageData>
#property (nonatomic, strong, readonly) CDChatMessage *chatMessage;
// main properties
#property (nonatomic, copy, readonly) NSString *text;
#property (nonatomic, copy, readonly) NSString *senderId;
#property (nonatomic, copy, readonly) NSString *watcherId;
...
#property (nonatomic, strong, readonly) JSQMessage *mediaMessage;
- (instancetype)initWithChatMessage:(CDChatMessage *)chatMessage;
#end
.m file could look like this:
#interface ChatMessageViewModel ()
#property (nonatomic, strong, readwrite) CDChatMessage *chatMessage;
// main properties
#property (nonatomic, copy, readwrite) NSString *text;
#property (nonatomic, copy, readwrite) NSString *senderId;
#property (nonatomic, copy, readwrite) NSString *watcherId;
...
#property (nonatomic, strong, readwrite) JSQMessage *mediaMessage;
#end
#implementation ChatMessageViewModel
- (instancetype)initWithChatMessage:(CDChatMessage *)chatMessage
if (self = [super init]) {
_chatMessage = chatMessage;
[self unpackViewModel];
}
return self;
}
- (void)unpackViewModel {
self.senderId = self.chatMessage.senderId;
self.text = self.chatMessage.senderId;
self.mediaMessage = [self unpackMediaData];
}
- (JSQMessage *)unpackMediaData {
// Here CDCustomPhotoMediaItem is a subclass of JSQPhotoMediaItem which just lets me create custom look of JSQ media item.
JSQPhotoMediaItem *photoItem = [[CDCustomPhotoMediaItem alloc] init];
return [JSQMessage messageWithSenderId:self.senderId displayName:#"" media:photoItem];
}
After I fetch data using NSFetchResultsController I just take all core data objects and turn them into immutable viewModels.
Then in cellForItemAtIndexPath I just call this:
cell.mediaView = [viewModel.media mediaView];
This approach creates nice immutable wrapper which contains only necessary chunk of information needed by the JSQ chat library. Also, you can easily write tests for such object. If you're using swift, you can use struct for this kind of purpose.
Hope my answer helps. Please ask if you need more detailed answer. ;-)
Can I replace an property with new one using some obj-c runtime features.
So I have a class A which contains a property:
#property (nonatomic, strong) Status *status;
So I want to inherit from this class like ClassB : ClassA and have ability to switch original #property (nonatomic, strong) Status *status; to my new property like #property (nonatomic, assign) NSInteger status;
So the reasone why I needed because I don't want to have a full copy of class A which contains 20 properties, so I just want to inherit from it and replace one with needed type.
Not sure if this possible, but I know something like swizzling and some obj-c runtime features can make a magic in the code.
I'm new to objective-C, so apologies if this is repeated somewhere. I have a category(?) that is something like:
inside SomeClass.h:
#interface SomeClass (SomeCategory) <SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#property (nonatomic, retain) id someProperty; // <-- i want to move this to "private"
#end
and now in my SomeClass.m, all i have is:
#implementation SomeClass (SomeCategory)
// dynamic setters/getters here for someProperty.
#end
I think the someProperty is public. how do i make this "private"? (in other words, how do i syntactically put this in the .m file? i tried to use
#interface SomeClass (SomeCategory) {
#property (nonatomic, retain) somePrivateProperty;
}
#end
but it just complains that i have duplicate definition of the category. how do i do this correctly?
In your .h file, you should not give the category. Just use:
#interface SomeClass : SomeBaseClass < SomeDelegate>
#property (nonatomic, retain) id somePublicProperty;
#end
In your .m file, define your private property inside a class extension:
#interface SomeClass ()
#property (nonatomic, retain) id somePrivateProperty;
#end
A class extension is not a like category in that it allows you to extend an interface as well as add new storage to your class.
In a class category, you can define new properties, but no storage will be allocated for it, so you have to do it by hand:
#interface SomeClass (SomeBaseCategory)
#property (nonatomic, retain) id somePrivateProperty;
#end
#implementation SomeClass {
id _somePrivateProperty;
}
- (void)setSomePrivateProperty:(id)property {
_somePrivateProperty = property;
}
- (id)somePrivateProperty {
return _somePrivateProperty;
}
#end
Otherwise your app will crash.
In any case, keep in mind that given the dynamic nature of Objective-C, your property will never be fully private, since you can always send a message to an Objective-C object through objc_msgsend and thus set or read the property value.
EDIT:
If you do not have the source code for a class implementation, you cannot define a class extension (as per source linked above).
In this case, you could use object association to define properties.
Just add the category definition in the .m file OUTSIDE the implementation block
Like so:
#interface MyClass (MyCategory)
#property (assign) BOOL myPrivateProperty;
#end
#implementation MyClass
...
#end
Categories are best used for adding capability to code you do not own and cannot change. Adding properties via categories is not impossible, but is much more difficult.
Class Extensions are best used for keeping properties your object needs, but are not intended to be public.
If you do truly need to add properties to this object, the way to do it is with the Objective-C runtime's associated objects
There's an excellent writeup of when/how to use them here
So here's my dilemma. I'm dealing with legacy code and trying to simplify and reduce a huge amount of redundancy in the code base. Here's the crux of the matter. I'm trying to consolidate two very similar classes into a superclass/subclass relationship. One is a subclass of NSObject the other a subclass of NSManagedObject.
I have a class that contains only variables called InventoryItems.h. It is a subclass of NSObject.
#property (nonatomic, retain) NSString * desc;
#property (nonatomic, retain) NSString * locationInventoryId;
...
InventoryItems.m
#synthesize desc;
#synthesize locationInventoryId;
...
There is another class that is called FavoriteInventoryItems.h that is a subclass of NSManagedObject.
It contains exactly the same variables as InventoryItems with one additional variable.
FavoriteInventoryItems.h
#property (nonatomic, strong) NSString * desc;
#property (nonatomic, strong) NSString * locationInventoryId;
#property (nonatomic, strong) NSString * dateAddedAsFav;
....
FavoriteInventoryItems.m
#dynamic desc;
#dynamic locationInventoryId;
#dynamic dateAddedAsFav;
...
I can successfully make things work by making InventoryItems a subclass of NSManagedObject and then making FavoriteInventoryItems a subclass of InventoryItems. It does work but I get a message indicating the following:
CoreData: error: Failed to call designated initializer on NSManagedObject class 'InventoryItems'
My solution assuredly is a hack that may have negative consequences.
There are multiple places where the code resembles something like the following:
if (InventoryItem)
...many lines of code here
else if(FavoriteInventoryItem)
...exact same code as above based on favorites
I'm not sure how else to consolidate both of these class into superclass/subclass relationship. Or is there a better way to handle this problem that doesn't involve inheritance? Any ideas?
Try to use a protocol to specify what is common between the classes and allow the 'using' code to be generic to the protocol.
The specification of a protocol is the important part, the implementation already exists in the 2 classes you have. The specification would list the common methods (or properties) between the 2 classes. Then, in the duplicated code, instead of saying:
InventoryItem *item = ...
or
FavoriteInventoryItem *item = ...
You would say:
id < InventoryItem > item = ...
I'm duplicating names because I can't know what a better name is, but the protocol is defined as:
#protocol InventoryItem < NSObject >
#property (nonatomic, strong) NSString * desc;
#property (nonatomic, strong) NSString * locationInventoryId;
#end
Then the code using the protocol doesn't care about what the underlying class is, it just cares what the protocol offers:
item.desc = #"Teddies";
item.locationInventoryId = ...
Sorry if this is stupid... but it confuses me?...
I'm trying a new storyboard app with Xcode and just asked myself why there is a second declaration of the #interface in my implementation file?
.h
#import <UIKit/UIKit.h>
#interface ViewController : UIViewController {
}
#end
.m
#import "ViewController.h"
#interface ViewController ()
#end
#implementation ViewController
....
#end
See Apple's documentation: https://developer.apple.com/library/ios/#documentation/Cocoa/Conceptual/ObjectiveC/Chapters/ocCategories.html
It's a class extension, subtly different from a category, since it has no name inside the parentheses. You use it for declaring properties and methods that are intended to be kept private (out of the header), and redeclaring publicly read-only properties and methods as privately read-write. This allows for cleaner encapsulation.
By request, a friendly example:
JYDuckPondManager.h
#interface JYDuckPondManager : NSObject
#property (nonatomic, assign, readonly) NSUInteger duckCount;
#property (nonatomic, assign, readonly) CGFloat waterLevel;
- (JYDuckReaction *)feedDucks:(JYDuckFood *)food;
- (JYDuckReaction *)harassDucks:(JYDuckTaunt *)taunt;
#end
JYDuckPondManager.m (extension, imaginary implementation omitted)
#interface JYDuckPondManager ()
//// Redefined for internal modification
#property (nonatomic, assign, readwrite) NSUInteger duckCount;
#property (nonatomic, assign, readwrite) CGFloat waterLevel;
//// Internally exclusive properties
#property (nonatomic, strong) NSSet *duckPersonalitySet;
#property (nonatomic, assign) CGFloat flockAnxietyLevel;
//// Private messages
- (void)recalculatePondState;
#end
Other objects should be able to interact with the pond, but they're not supposed to know certain things going on in the pond or redefine the pond's statistics. Keeping nuts-and-bolts stuff in the .m extension ensures that the .h is concise and appropriately limited.
The second #interface block in the .m file is an extension. You could add declarations for methods and instance variables you want to use internally within your class.
The second interface #interface ViewController () is a class extension which is like an anonymous category. A class extension is declared like a category only without a name. Declarations found in these extensions directly extend the declarations found in the class’s primary #interface and can sometimes (in some situations) override declarations found in the primary interface.