make class cluster

  • I am uncertain how to construct a class-cluster and cannot find all I
    should know in the ObjC and Cocoa guides (the montharray example in
    the latter is kind of special). Let me describe the setup I have in
    mind.

    Two classes are to be made, having many methods in common but
    differing in the init method and how they produce their result. Hence
    the idea of making a class-cluster.

    The idea is now:

    1. The class-cluster class is merely a dispatcher of the worker classes.
    2. Each of the three classes (cluster class and two work classes)
    descends directly from NSObject and thus they are independent classes.
    3. The cluster class is called with [[cluster-class alloc] init...]
    and dispatches a work class by returning [[work-class alloc] init...]

    Questions I could not satisfactorily answer myself:

    1. Is the setup of three independent classes correct or should I make
    the two work classes a subclass of the cluster class? The common code
    can then be shared through the cluster class.

    2. In the sequence [[cluster-class alloc] init...] should I release
    self? Thus in the cluster-class as init for the production of a work
    class:
      - (id) init... {
          [self release]; // needed??? too early at this point???
          id worker = [[worker alloc] init...];
          return worker;
      }

    I would appreciate your expert insight. Thanks in advance.

    Hans van der Meer
  • On Oct 6, 2007, at 8:10 AM, Hans van der Meer wrote:

    > I am uncertain how to construct a class-cluster and cannot find all
    > I should know in the ObjC and Cocoa guides (the montharray example
    > in the latter is kind of special). Let me describe the setup I have
    > in mind.
    >
    > Two classes are to be made, having many methods in common but
    > differing in the init method and how they produce their result.
    > Hence the idea of making a class-cluster.
    >
    > The idea is now:
    >
    > 1. The class-cluster class is merely a dispatcher of the worker
    > classes.
    > 2. Each of the three classes (cluster class and two work classes)
    > descends directly from NSObject and thus they are independent classes.
    > 3. The cluster class is called with [[cluster-class alloc] init...]
    > and dispatches a work class by returning [[work-class alloc] init...]
    >
    > Questions I could not satisfactorily answer myself:
    >
    > 1. Is the setup of three independent classes correct or should I
    > make the two work classes a subclass of the cluster class? The
    > common code can then be shared through the cluster class.

    Hey Hans,

    I really think your best option is to encapsulate all concrete work
    classes and hide them from external use, rather than require that
    users of the class cluster possess knowledge of not only the cluster
    interface itself but also each subclass interface as well.
    Implementing behavior in this manner is consistent with the Abstract
    Factory design pattern.  An Abstract Factory-based cluster
    encapsulates object creation and results in loose coupling because
    external code does not depend on a multitude of concrete classes.

    External users of your class cluster can be shielded from the fact
    that a different object (a subclass of the cluster) is returned
    rather than a direct instance of the cluster itself.  The way to hide
    this fact is by allowing the object to respond to all methods
    declared in the cluster's public interface.  The goal is to simplify
    the external code using the cluster, and encapsulate the actual
    determination of which unique subclass to use into one area, the
    cluster's init method, rather than having multiple places in your
    external code responsible for figuring out which subclass is
    appropriate and then creating it.  This also makes your code more
    maintainable - if you decide another subclass is needed you can
    introduce it in only one area, the cluster's init method.

    As an example of a class cluster I'm working on for Camino:

    We want to parse search plugins, and decided not to couple ourselves
    to a certain plugin file format.  I made a public, generic, parsing
    interface that serves as the class cluster, and then have separate
    objects which handle the parsing of each particular format.  The
    responsibility of determining which subclass to use is moved out of
    the client code (which is a maintenance problem because each time we
    support a new format we'll need to change all locations of our code
    that creates one of these subclasses) and into the cluster itself.

    Here's a basic example of what I mean (I threw this together real
    quick in Mail, so don't go nuts critiquing it)

    // Our Class Cluster's Abstract Interface
    @interface SearchPluginParser

    - (id)initWithPluginMIMEType:(NSString *)mimeType;

    // Abstract method, implemented by private subclasses:
    - (BOOL)parsePluginAtURL:(NSUrl *)pluginURL;

    // Some accessors:
    - (NSURL *)searchPluginURL;
    - (NSString *)searchPluginName;

    @end

    // Private subclass, known only to SearchPluginParser, which it uses
    to parse a certain file format:
    @interface OpenSearchParser : SearchPluginParser
    ...
    @end

    @implementation OpenSearchParser
    // Implement those abstract methods in the cluster with the knowledge
    of how to parse this unique format.
    @end

    And, the class cluster (SearchPluginParser) init method:
    @implementation SearchPluginParser

    // Returns nil if type is not supported.
    - (id)initWithPluginMIMEType:(NSString *)mimeType
    {
        [self release];
        // This is where you'd determine which concrete subclass can
    best handle the situation
        if ([mimeType isEqualToString:kOpenSearchType])
          self = [[OpenSearchParser alloc] init];
        else
            self = nil;
        return self;
    }

    ... (define any other default implementations for public methods,
    such as the accessors)

    @end

    ----

    Externally, the code using the cluster:

    - (void)detectedSearchPlugin:(NSDictionary *)searchPluginInfoDict
    {
      SearchPluginParser *pluginParser =  [[SearchPluginParser alloc]
    initWithMIMEType:[searchPluginInfoDict
    objectForKey:kSearchPluginMIMETypeKey]];
      // Check return value and then call methods declared publicly in
    SearchPluginParser.h, essentially treating the returned object as a
    SearchPluginParser, even though it's actually a subclass of it.
      // We know nothing about OpenSearchParser here.
    }

    The cluster's init method should have the knowledge to determine
    which private, concrete subclass to actually implement the required
    behavior.  Now, if we decide to add another plugin format, the client
    code shouldn't need to change at all - the cluster would introduce
    the new private subclass and handle the new behavior.

    >
    > 2. In the sequence [[cluster-class alloc] init...] should I release
    > self? Thus in the cluster-class as init for the production of a
    > work class:
    > - (id) init... {
    > [self release]; // needed??? too early at this point???
    > id worker = [[worker alloc] init...];
    > return worker;
    > }

    Yes.  See Bill Bumgarner's excellent example at: <http://
    www.cocoabuilder.com/archive/message/cocoa/2007/5/25/183673>

    I hope this helps,
    -Sean
  • On 6 Oct 2007, at 13:10, Hans van der Meer wrote:

    > I am uncertain how to construct a class-cluster and cannot find all
    > I should know in the ObjC and Cocoa guides (the montharray example
    > in the latter is kind of special). Let me describe the setup I have
    > in mind.
    >
    > Two classes are to be made, having many methods in common but
    > differing in the init method and how they produce their result.
    > Hence the idea of making a class-cluster.
    >
    > The idea is now:
    >
    > 1. The class-cluster class is merely a dispatcher of the worker
    > classes.
    > 2. Each of the three classes (cluster class and two work classes)
    > descends directly from NSObject and thus they are independent classes.
    > 3. The cluster class is called with [[cluster-class alloc] init...]
    > and dispatches a work class by returning [[work-class alloc] init...]
    >
    > Questions I could not satisfactorily answer myself:
    >
    > 1. Is the setup of three independent classes correct or should I
    > make the two work classes a subclass of the cluster class? The
    > common code can then be shared through the cluster class.

    Firstly, let's clarify the terminology here a little. In the case of
    a class cluster, you have the "abstract" class (not "cluster"), and
    then any number of "concrete" subclasses/implementations.

    So, to answer the original question; by definition, your concrete
    implementations should be subclasses of the abstract class. a)
    because this allows you to share common code, and b) because it
    ensures there is a consistent API across the classes, keeping the
    compiler happy.

    >
    > 2. In the sequence [[cluster-class alloc] init...] should I release
    > self? Thus in the cluster-class as init for the production of a
    > work class:
    > - (id) init... {
    > [self release]; // needed??? too early at this point???
    > id worker = [[worker alloc] init...];
    > return worker;
    > }

    You should indeed release self otherwise this could turn into a
    rather large memory leak. It's much the same as Apple's advice for
    when there is an error instantiating a class - the init method should
    [self release] and then return nil.
    >
    > I would appreciate your expert insight. Thanks in advance.
    >
    > Hans van der Meer
previous month october 2007 next month
MTWTFSS
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        
Go to today