Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

A Not-as-Clumsy OOP Implementation?

by billyak (Friar)
on Aug 25, 2001 at 17:29 UTC ( [id://107818]=perlquestion: print w/replies, xml ) Need Help??

billyak has asked for the wisdom of the Perl Monks concerning the following question:

I've been working on a project that has recently turned into something I'd like to attempt to convert to OOP. I've messed with OOP in the past, but most I've put together in an attempt at it were pretty wretched. In the past I've tried to work things out on my own, but I've spent far too long writing bad code. I turn to my fellow monks for assistance.

Here is the general idea and the implementation (or my excuse of one).

Monitor port ###
Get packet
Parse packet
Compare packet information with hash (or maybe an external DB later)
** Send packet out, do other things, general action based on packet content
(It looks so much simpler when I type it out ;-)

Thats the goal. So here is the clencher. I want it to be a somewhat modular system for adding new events (at the **'s part.) Right now I've got a Monitor package that I would like to have run things, and a Function package to hold all of the "functions" (the ** code.) Here is some relevant code (constructors and other vital code omitted):

my $monitor = new Monitor; $monitor->add_function("3","blah"); package Function; sub blah { if(wantarray){return(qr{blah ?(.+)?})} # Useful code will eventually go here } package Monitor; sub add_function { my($self,$access,$name) = @_; my $ref = \&{"Function::$name"}; my($regexp) = $ref->(); $FUNC{$regexp}{access} = $access; $FUNC{$regexp}{code} = $ref; }
Then I would get packets, loop through the $FUNC keys, applying the regexes and sending the data to the appropriate subs when the regex was a match.

For some reason, I think there is a much better way to do this. The name space is also really messy. Ideally, I'd want several hashes and a few object refs to be globally accessible across packages; no doubt that is an obvious sign of bad code.

Hopefully I have done an adequate job at showing what I am trying to achieve. I would really appreciate any suggestions or comments anyone could contribute. Thanks.

-billyak

Replies are listed 'Best First'.
Re: A Not-as-Clumsy OOP Implementation?
by bikeNomad (Priest) on Aug 25, 2001 at 18:46 UTC
    One way to handle this is to use a Factory pattern, where the product of the Factory is an object whose type depends on the packet content.

    You can use polymorphism to get the varying behavior of these objects.

    One simple way to do it is this:

    package Packet; my %patterns; # could add some in declaration sub addType { my $regex = shift; my $className = shift; $patterns{$className} = $regex; } sub removeType { my $className = shift; delete $patterns{$className}; } sub makeOnePacket { # get a packet my $packet = getAPacket(); return undef unless $packet; my $newObject; my ( $className, $regex ); while ( ( $className, $regex ) = each(%patterns) ) { my @fields; if ( @fields = ( $packet =~ $regex ) ) { $newObject = $className->new( $packet, @fields ); last; } } $newObject; } # These two must be defined by classes that want # to work with this system. sub newFromPacket { my $class = shift; my $packet = shift; my @fields = @_; # initialize as needed, return object. bless { packet => $packet, fields => \@fields }, $class; } sub process { my $self = shift; # now do whatever is necessary } package main; Packet::addType( qr/^(abc)(.*)/, 'SomeType' ); Packet::addType( qr/^(def)(.*)/, 'SomeOtherType' ); while ( my $newPacket = makeOnePacket() ) { $newPacket->process(); }

    Note that now you can add new packages that work with this system by just including them. Stick the following in NewPacket.pm:

    package NewPacket; use Packet; # Could have inherited from Packet, but no # reason to. Luckily, this isn't Java or C++. sub newFromPacket { my $class = shift; my $packet = shift; my @fields = @_; # initialize as needed, return object. bless { packet => $packet, fields => \@fields }, $class; } sub process { my $self = shift; } # you could also use __PACKAGE__ here: Packet::addType( qr/^(something)(.*)/, 'NewPacket' ); Packet::addType( qr/^(somethingElse)(.*)/, 'NewPacket' ); # returns + true

    Then a simple use NewPacket; in your main will add the new functionality.

    update: added explanation about adding new types.

Re: A Not-as-Clumsy OOP Implementation?
by Aighearach (Initiate) on Aug 25, 2001 at 18:49 UTC
    You might want to not use the Function package that way. Better would be to put your code refs in a hash. Then you can just eval the hash value, instead of using $ref->(). That's very bad to do when $ref is being set by input! Also, why are you adding functions that have to already be in the namespace? They're already there, you don't add them to anything, just call them. What I use for something similiar is an array of hashes, the hashes containing name, regex, and code entries. Then I can loop through the array, test each regex against the input, and execute the code if it matches. Also, I can just add a hash ref to plug in a function, no need to mess with the namespace at runtime.

    But that is all that is gained by all that, being able to plug in extra parsers without restarting. Usually that's not needed... I usually only do it in the case of network bots that have to interact with users. Generally, it's best to just stick to the exact methodologies used in the "perltoot" Perl documentation. If you don't see it in there, it's probably a sign to rethink the implementation.

    Another important thing is, I don't see a use strict or a use warnings. Probably you just trimmed that part to make your post concise, but you need to include those so we know that you're not just digging holes for yourself. Without strict mode and warnings, there is no salvation.

Re: A Not-as-Clumsy OOP Implementation?
by jepri (Parson) on Aug 25, 2001 at 20:54 UTC
    I recently have been working on a similar project (it's open in the other window, that's how recent it is...). I tend to rip off other peoples ideas ( I just call it 'taking inspiration') and this model has been solved before, by the ipchains/iptables people.

    My OO - fu is a bit weak, the only two objects that need to be objects in the examples below are the packets (which I use to unpack/pack the binary stream) and the packet engines (which maintain state, sockets and other neat stuff). The tally and function objects may as well be straight functions, but if you're going OO, you may as well go the whole hog.

    As near as I can tell the goal of OO is to combine data and code, so anytime you see data, you want to attach code to it. Thus the packets should be objects, and so should the engines. Otherwise you just have modular code, i.e. modules, which perl already does fine. This approach also minimises your packet variables, and notice - no true globals.

    ---Broad outline: Get packets Tally stats Mangle them Tally stats Send 'em out B---road outline, 10x magnification: Get packets from packet engine Run them through the tally object Mangle packets with custom packet mangler (TM) Tally object... Send them out through the packet engine ---Broad outline, 100x mag: foreach $packet_engine ( @all_packet_engines ) { push @incoming_packet_queue, $packet_engine_object->get_packets; } $stats_object->tally(@incoming_packet_queue); @outgoing_packet_queue = $function_object->mangle(@incoming_packet_que +ue); @incoming_packet_queue = (); $stats_object->tally(@outgoing_packet_queue); foreach $packet ( @outgoing_packet_queue ) { #insert clever routing logic for packets e.g. foreach $engine ( @all_packet_engines ) { if ( $packet->{ATTRIB} == $engine->{ATTRIB} ) {$engine->send($packet) +} } }

    now all you have to do is fill in the thousands of lines of code for each object. It's 3am, so maybe it's not so clear. Read up on ipchains for the idea I'm working with here.

    To make it more like ipchains, you would have multiple function objects (or multiple routines in the function object), and allow the objects(functions) to pass the packet to each other. Each function would mangle the packet until one of them passed it to the output routing object.

    ____________________
    Jeremy
    I didn't believe in evil until I dated it.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others avoiding work at the Monastery: (3)
As of 2024-04-25 17:33 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found