Search code examples
perlmoose

How can I invoke an object dynamically in Perl Moose OOP?


Here is classical object model:

 class ViewBase
 {
  void DoSomethingForView() { } //May be virtual
 }

 class View1 : ViewBase //(derived class from ViewBase)
 {
    void DoSomethingForView() { }
    void DoSomethingForView1Special() { }
 }

 class View2: ViewBase //(another derived class from ViewBase)
 {
    void DoSomethingForView2Special() { }
 }

 class Application
 {
    void Print() { }
    void DoSomething() { }

     //Do some magic to create a view object (View1 or View2) and return

    //Something which I don't know to describe. Its like dynamically 
    //returning object of View1 or View2 at runtime
  }

I want to convert this to Perl Moose class model.

So that,

I will call the view methods like

void Main()
{

  App = new Application();

  App->View1->DoSomethingForView(); 
  App->View1->DoSomethingForView1Special();
  App->View2->DoSomethingForView(); 
  App->View2->DoSomethingForView2Special();

}

I will not know which View to be called. But at runtime, View1/View2 instance must be created & DoSomethingForView() must be called.

The above code is not exactly Perl. How to translate & achieve this in Perl.

An Application object shall have View object, but we will not know the type of the view at compile time. We have a test application, development in Perl.

You can imagine Application is a GUI application, and View is what you are seeing in the application window. User can select any view.

I am sorry about my English. Please let me know If I need to provide more text.


Solution

  • So this gives you roughly equivalent syntax in Perl. It doesn't help you out with some of your conflicting criteria, though.

    Note the following:

    • class ABC {...} is replaced by the perl syntax package ABC;
    • The capital camel-case method names are turned into proper "snake-case" perl.
    • App has been turned to sigil-ed $App

    This has been tested against Moose v62, Perl 5.10. Second from the last line will fail, because do_something_for_view is not implemented by View2 class. As you're calling view1 or view2 specifically, I don't see the application for what you seem to indicate is polymorphism.

    package ViewBase;
    
    sub do_something_for_view { 
        Carp::croak "ViewBase::do_something_for_view is ABSTRACT!"; 
    }
    
    package View1;
    use Moose;
    extends 'ViewBase';
    
    sub do_something_for_view { print "Doing something for View1.\n"; }
    sub do_something_for_view1_special { print "Doing something SPECIAL for View1.\n"; }
    
    package View2;
    use Moose;
    extends 'ViewBase';
    
    sub do_something_for_view2_special() { print "Doing something SPECIAL for View2.\n"; }
    
    package Application;
    use Moose;
    
    has view1 => ( 
          is      => 'rw'       # read/write
        , isa     => 'View1'
        , lazy    => 1
        , default => sub { View1->new(); } 
        );
    
    has view2 => ( 
          is      => 'rw'       # read/write
        , isa     => 'View2'
        , lazy    => 1
        , default => sub { View2->new(); } 
        );
    
    sub print {}
    sub do_something {}
    
    #void Main()
    #{
    
    package main;
    
      #App = new Application();
    my $App = Application->new();
    
      #App->View1->DoSomethingForView(); 
    $App->view1->do_something_for_view();
      #App->View1->DoSomethingForView1Special();
    $App->view1->do_something_for_view1_special();
      #App->View2->DoSomethingForView(); 
    $App->view2->do_something_for_view();
      #App->View2->DoSomethingForView2Special();
    $App->view2->do_something_for_view2_special();
    
    #}