comp.lang.ada
 help / color / mirror / Atom feed
From: Matthew Heaney <mheaney@on2.com>
Subject: Re: Factory Pattern
Date: Wed, 25 Jul 2007 12:27:59 -0700
Date: 2007-07-25T12:27:59-07:00	[thread overview]
Message-ID: <1185391679.375281.277550@k79g2000hse.googlegroups.com> (raw)
In-Reply-To: <1185387571.367570.163160@r34g2000hsd.googlegroups.com>

On Jul 25, 2:19 pm, shaunpatter...@gmail.com wrote:
>
> My code looks something like this:
>
> type Message is abstract tagged;

You need to say more here, but see below.


> type Message_Class is access all Message'Class;

In Ada05 you might not need this access type, since functions can now
return an anonymous access value.

Also, if you want to force clients of your abstraction to call your
constructor, you should probably declare the type as limited:

  type Message is abstract tagged limited null record;

If your root type has payload that you want to make private, then you
can say:

  type Message is abstract tagged limited private;
  ...
private
  type Message is abstract tagged limited record ... end record;


> derived type:
>
> package MessageInteger_Pkg is

You probably want to declare the partial view of your type in the
public part, and with an unknown discriminant:

  type MessageInteger (<>) is new Message with private;


>
> -- I want this to act like a constructor
> -- Just fills in the value
> function create (i : Integer) return MessageInteger;
>
> private
> type MessageInteger with new Message with
> record
>       value : Integer;
> end record;
>
> end MessageInteger_Pkg;
>
> -- create looks like this:
> function create (i : Integer) return MessageInteger is
>      msg : MessageInteger;
> begin
>      msg.value := i;
>      return msg;
> end create;

This won't work if the type is limited.  You can say either:

  function Create (I : Integer) return MessageInteger is
  begin
     return (Value => I);
  end;

or

  function Create (I : Integer) return MessageInteger is
  begin
     return Result : MessageInteger do
        Result.Value := I;
     end return;
  end Create;


> Factory method:
>
> -- I would like it to work like this...
> function createMessage (type : Integer) return Message_Class is
> begin
>          case type is
>                  when 0 =>
>                       return MessageInteger_Pkg.create (1234);
>                  when others =>
>                        return MessageSomethingElse_Pkg.create
> ("blah");
>          end case
>
> end createMessage

You can do this:

  function CreateMessage (T : Integer) return Message'Class is
  begin
     case T is
        when 0 =>
           return MessageInteger_Pkg.Create (T);
        when others =>
           return MessageSomethingElse_Pkg.Create;
     end case;
   end CreateMessage;

This avoids any use of pointers.  This might or might not be what you
need.  Another possibility is:

  function CreateMessage (T : Integer) return not null access
Message'Class is
  begin
     case T is
        when 0 =>
           return MessageInteger_Pkg.Create (T);
        when others =>
           return MessageSomethingElse_Pkg.Create;
     end case;
   end CreateMessage;

(You'll have to also change the ctors for each derived type to return
an access value designating the specific type.)


> However - it doesn't like me returning the MessageInteger from a
> class
> that returns a Message_Class (obviously..)

Right, because (in your original example) MessageInteger_Pkg.Create
returns a value of the type, while CreateMessage returns an access
value.


> Now if I do this -- changing the constructor to take in a
> Message_Class....
>
> function createMessage (type : Integer) return Message_Class is
>       decodedMessage : Message_Class;
> begin
>          case type is
>                  when 0 =>
>                       decodedMessage := new
> MessageInteger_Pkg.MessageInteger;
>                        MessageInteger_Pkg.create (decodedMessage,
> 1234);        -- change the decoded message this way
>                        return decodedMessage;
>                  when others =>
>                        return MessageSomethingElse_Pkg.create
> ("blah");
>          end case
>
> end createMessage
>
> -- That method works... but I find the intermediary step of making a
> new object decodedMessage
> to someone unneeded?  There must be another way of doing this.
> Perhaps I should move the "new"
> to the create function?

Yes, move the new to the Create function for each derived type.
(There are others ways of solving this problem, but that will at least
get you going.)


> And... I'm not completely sure I'm doing all this correctly in Ada.
> LIke I said,  I'm very new to
> Ada.

That's OK.  That's what CLA is for.  Welcome!

-Matt




  parent reply	other threads:[~2007-07-25 19:27 UTC|newest]

Thread overview: 26+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-25 18:19 Factory Pattern shaunpatterson
2007-07-25 18:28 ` Martin
2007-07-25 18:51 ` Dmitry A. Kazakov
2007-07-25 21:06   ` Georg Bauhaus
2007-07-25 19:27 ` Matthew Heaney [this message]
2007-07-26  0:51 ` Jeffrey R. Carter
2007-07-26  6:44   ` Maciej Sobczak
2007-07-26  8:40     ` Georg Bauhaus
2007-07-26  9:53       ` Dmitry A. Kazakov
2007-07-26 11:01         ` Georg Bauhaus
2007-07-26 13:02           ` Maciej Sobczak
2007-07-26 13:44             ` Dmitry A. Kazakov
2007-07-26 14:58             ` Georg Bauhaus
2007-07-26 22:31             ` Randy Brukardt
2007-07-27 13:07               ` Maciej Sobczak
2007-07-27 14:23                 ` shaunpatterson
2007-07-27 22:23                 ` Randy Brukardt
2007-07-28 18:56                   ` Maciej Sobczak
2007-07-29  7:54                   ` Maciej Sobczak
2007-07-29  8:53                     ` Dmitry A. Kazakov
2007-07-29 10:53                     ` Georg Bauhaus
2007-07-26 16:58         ` Adam Beneschan
2007-07-29 11:38         ` Manuel Gomez
2007-07-27 10:16     ` Jeffrey R. Carter
2007-07-27 12:47       ` Maciej Sobczak
2007-08-26  7:18         ` David Thompson
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox