On 2 February 2011 00:10, James Moschou <[email protected]> wrote:
> Hello,
>
> I have an abstract class, which has a named constructor and would like
> to be able to create instances of concrete subclasses by passing the
> type to a factory method. Specifically:
>
> abstract class Document : Object {
>  Document.with_name (string name) { ... }
> }
>
> class TextDocument : Document {
>  TextDocument.with_name (string name) { ... }
> }
>
> Document get_document_with_name (string name, Type document_type) {
>  // Something here ...
> }
>
> // Usage
> TextDocument text_document = (TextDocument) get_document_with_name
> (name, typeof (TextDocument));
>
>
> I have a feeling such a thing is possible using GObject constructor
> properties and the construct block, but I'm not sure how. I've been
> avoiding doing object construction the GObject way up until now, and
> would prefer to keep doing so if possible as it is simpler to
> understand.
>
> Also this factory method is just for a special case, i.e. the normal
> way to create documents is actually using the new keyword. So if I
> have to use GObject construction, I would prefer it to be alongside
> the normal constructors; is this possible? The documentation I've read
> seems to assume it's one or the other.
>
> Regards,
> James
>

I think I've managed to solve this in a robust, if a bit convoluted
way. It involved delegating the initialisation code out of the
constructors to virtual init... methods. Utilising virtual methods is
what allows the factory method to work.

Then I used the concept of a "designated initialiser" to ensure the
classes would chain up in the correct order, without weird behaviour
happening with overridden virtual methods.

http://developer.apple.com/library/mac/#documentation/cocoa/conceptual/ObjectiveC/Articles/ocAllocInit.html
(about half way down)

Altogether:

abstract class Document : Object {
  Document () {
    init ();
  }
  Document.with_name (string name) {
    init_with_name (name);
  }
  // init is the designated initaliser
  virtual void init () { ... }
  virtual void init_with_name (string name) {
    init ();
    ...
  }
}

class TextDocument : Document {
  TextDocument () {
    base ();
  }
  TextDocument.with_name (string name) {
    base.with_name ();
  }
  // init here is also the designated initialiser
  // so it chains up to the base designated initialiser
  override void init () {
    base.init ();
  }
  override void init_with_name (string name) {
    init ();
    ...
  }
}

Document get_document_with_name (string name, Type document_type) {
  Document doc = (Document) Object.new (document_type);
  doc.init_with_name (name);
  return doc;
}


This way initialisers get called:
1. Document.init ()
2. TextDocument.init ()
3. TextDocument.init_with_name ()

whether using Object.new() or normal construction.

I know this probably seems like I'm trying to replicate another
programming environment's paradigm where it doesn't belong, but I
can't use construct properties, because that forces you to store the
passed arguments as properties. I might choose to interpret 'name' as
a filepath and store the File object, or just process 'name' without
storing anything, etc.

Regards
James
_______________________________________________
vala-list mailing list
[email protected]
http://mail.gnome.org/mailman/listinfo/vala-list

Reply via email to