Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Where do new methods go?

Let's say I have an object, Car, and it has sets of methods that are... disparate? Maybe getting Blob-like? (as in the antipattern, "blob") These methods operate in distinct enough sets and don't really criss-cross functionally.

Car
# methods related to suburban driving
  ->foo1
  ->foo2
# methods related city driving
  ->bar3
  ->bar4

Now let's say I wanted to add "off road driving" as one of the cases that my car object can support. If I add methods to the Car object, isn't that making it more blob like?

Car (augmented)
# methods related to suburban driving
  ->foo1
  ->foo2
# methods related city driving
  ->bar3
  ->bar4
# methods related off road driving
  ->blah5
  ->blah6

Should I:

A: Subclass Car. I can make an OffRoadCar extends Car object. But what if Car and OffRoadCar share the same data/state, and only differ by methods? OffRoadCar only "acts" more specifically than car, but isn't described any more specifically nor does it have unique fields. So instantiating an OffRoadCar is meaningless.

OffRoadCar extends Car
# methods related off road driving
  ->blah5
  ->blah6

B: Consume Car with a Static Method. Like OffRoadAdventure->Embark(Car). So the OffRoadAdventure class takes a Car object and has its way with it.

In C# this would be called an extension method.

I guess put another way is what is the solution to the Blob antipattern? Is it subclassing? Is it extension methods?

Also, another reason I wanted to silo out these methods is what if their implementation incurs some cost, like the inclusion of other classes/packages? I wouldn't want users of the core class to constantly pay for something they would never use. I figure making the cost explicit for the minority is worth the savings for the majority. And it makes the dependency graph more precise (and not blob-like).

PS - Implementation language is Perl.

like image 550
Mark Canlas Avatar asked Nov 05 '22 05:11

Mark Canlas


1 Answers

With Perl you should be taking a good look at Moose and roles.

package Suburban;
use Moose::Role;

requires 'wheels';

sub 'foo1' {
  ...
}


sub 'foo2' {
  ...
}

package City;
use Moose::Role;

requires 'wheels';

sub 'bar3' {
  ...
}


sub 'bar4' {
  ...
}

package Offroad;
use Moose::Role;

requires 'wheels';

sub 'blah5' {
  ...
}


sub 'blah6' {
  ...
}

package UltraCar;
use Moose;

with qw/ Offroad City Suburban /;
has 'wheels' => ( is => 'rw', isa => 'Int', default => 4 );

package RentalCar;
use Moose;

with qw/ City Suburban /;
has 'wheels' => ( is => 'rw', isa => 'Int', default => 4 );

package Tricycle;
use Moose;

with qw/ Offroad /;
has 'wheels' => ( is => 'rw', isa => 'Int', default => 3 );

You can even add and remove roles at runtime.

like image 122
Oesor Avatar answered Nov 10 '22 18:11

Oesor