Beefy Boxes and Bandwidth Generously Provided by pair Networks
Pathologically Eclectic Rubbish Lister
 
PerlMonks  

Re: Designing multiple related modules

by bliako (Monsignor)
on May 12, 2021 at 13:22 UTC ( [id://11132478]=note: print w/replies, xml ) Need Help??


in reply to Designing multiple related modules

I am in favour of (2) creating an "interface" although I would call it "base class" because it will have common functionality implemented in there, centrally and for once. For example a toString() method or export/import_session() which would not be in general needed to be overwritten by subclasses.

An advantage of this is that 3rd party developers can contribute implementation classes for different social media while the API is centrally controlled. Provided that there is indeed a common API with these and future social media sites (hmm not so sure about that).

An example for the above is HTTP::Cookies and the large number of subclasses (by different contributors) overwriting its load() and save() methods for various browsers and cookie standards. The key point is: contributions by 3rd party. And the biggest problem is for you to identify the API and make sure it will be generic and can survive in time, respecting the contributions by others.

PS. I may be missing something but (4) Factory works in conjuction with (2), not as an alternative.

bw, bliako

Replies are listed 'Best First'.
Re^2: Designing multiple related modules
by Fletch (Bishop) on May 12, 2021 at 13:59 UTC

    Agree with your PS. A factory is the way you hide your implementation classes (quoth c2: "It allows classes to defer object creation to a separate method") from callers who just use that API to obtain the specific flavour they're wanting with something like Bod::Social->new_for( 'Twitter' ) rather than explicitly hardcoding creating an instance of a specific subtype. End users just know they're getting something that isa Bod::Social and can expect it to provide that same interface specialized for their particular kind of thing. You also don't have to go change callers to have them instead instantiate Bod::Social::NewTwitter n months hence when you create a new subclass which is faster or handles some new wrinkle; change the factory and callers get the improved version without knowing they have to ask for it.

    Prossibly not germane in this particular case but if all of the different "flavors" vary only in how to implement some common behavior you might could use Strategy to implement that instead of having full subclasses for each network/type (although you might still want to use a factory method for instantiating the different strategy implementations).

    Or it could just be too early and ENOCAFFEINE and I'm rambling . . .

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

      Yes, I agree to your agreement. Do you have any proposal for "who owns the Factory" when Bod owns the "interface"/base-class and 3rd party develop different subclasses to it? Someone has to update the Factory...

        Hmmm . . . that's a good question; I was mostly thinking of this as the namespace being controlled by the factory author and not an open namespace with 3rd party implementors.

        Maybe some sort of registry/plugin system that new subclasses could ask to be added to and/or be automatically added to if present in some special namespace but that (admittedly very handwavy vague idea) would be all I can come up with off the top of my head. Were my arm twisted I'd look to Java-land and see what sort of approach they take there (and some large grains of salt as well since it's not necessarily going to translate 1-to-1). I think there's stuff like how log4j handles this sort of thing similar problems with runtime specification of logging providers or backends that might provide inspiration.

        Edit: tweaked l4j phrasing.

        Edit again: Slightly (marginally so) more concrete thoughts: Mojolicious::Plugins might be another place to look for inspiration. Or Module::Pluggable, where the factory could consult each class in $self->plugins and if they have a register_social_class method call that (which returns maybe a list of the key it wants to be known by and a coderef to call to get an instance).

        The cake is a lie.
        The cake is a lie.
        The cake is a lie.

Re^2: Designing multiple related modules
by Bod (Parson) on May 12, 2021 at 16:34 UTC
    PS. I may be missing something but (4) Factory works in conjuction with (2), not as an alternative

    I my mind, (2) would involve creating an instance of the subclass directly through Bod::Social::Twitter->new whereas (4) would rely on the factory class to create the subclass with Bod::Social::Factory->new(network => 'Twitter')

    I think that (3) and (4) are probably the same thing but with just different terminology...aren't they?

      Well, again I would call the Factory not a class but a package with a "static" method: Bod::Social::Factory::new_for(network => 'Twitter') (borrowing from Fletch's comment above). Perl makes that distinction possible whereas I guess in Java it would technically be a class. OTOH, why not if it suits you?

      That said, and purisms aside, I would expect the constructor of a class to return ... erm ... an object of that same class. In Java, I hope I guess correctly, it is impossible for a constructor to return anything other than the object of that class (there is no return statement as such). So, Bod::Social::Factory->new(network => 'Twitter') returning TwitterClass or XYZClass or ... depending on input params strikes me as a bit weird, or unexpected. Where Bod::Social::Factory::new_for(network => 'Twitter'); (notice the difference in ::new_for) is more intuitive for me. But even TIMTOWTDI is spelled in many ways hehe!

      Now, what would be inside new()/new_for()? I would put in there this:

      use Bod::Social::Twitter; sub new_for { my ($network, $params) = @_; if( $network eq 'Twitter' ){ return Bod::Social::Twitter->new($param +s) } elsif( ... ){ ... } die "don't know network $network" }

      Which also implies a class Bod::Social::Twitter, which can be a subclass of Bod::Social (option (2)) or be completely independent, if you did not find enough common ground to create a social API in Bod::Social

      That was helpful to me: https://www.tutorialspoint.com/design_pattern/factory_pattern.htm, but thankfully Perl is way less restrictive than Java.

      bw, bliako

        I would expect the constructor of a class to return ... erm ... an object of that same class

        Yes...that's kind of obvious but until you mentioned it wasn't front of mind.

        Having the constructor return the same class or a subclass of it has been added to my mental list of things to make sure of when creating a new module.

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://11132478]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others musing on the Monastery: (6)
As of 2024-05-18 03:16 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found