ООП / Процедурные вопросы дизайна - PullRequest
4 голосов
/ 24 августа 2011

У нас есть несколько сторонних библиотек Perl для передачи файлов в / из и, кроме всего прочего, для шифрования / дешифрования файлов с использованием PGP. В настоящее время эти библиотеки используют избыточный код и выполняют вышеупомянутые методы, используя system() и двоичные файлы командной строки.

Я хочу переписать эти библиотеки, используя больше модулей и ООП, где это необходимо. В настоящее время я размышляю над тем, как я хочу настроить основную библиотеку, включая сценарии Perl для использования Net::SFTP для размещения / получения файлов и Crypt::PGPSimple для шифрования / дешифрования файлов.

Должен ли библиотечный модуль быть написан на ООП? Имеет ли это смысл? Или следует импортировать (и разрабатывать процедурно) методы по мере необходимости и создавать объекты Net::SFTP и Crypt::PGPSimple по мере необходимости? Я просто не уверен, что хочу создать объект Lib и инициализировать SFTP, PGP, Constants и т. Д. В подпункте new. Я полагаю, что этот тип класса больше похож на класс Java со статическими методами, но должен быть только один объект / соединение SFTP (не уверен, что Net::SFTP уже позаботился об этом?) И один Crypt::PGPSimple и т. Д.

Кроме того, возвращаясь к избыточности, эта библиотека также должна иметь родительский элемент, который определяет функции, которые используют многие сторонние библиотеки (FTP, PGP и т. Д.).

Я не ищу определенного ответа, потому что, вероятно, его нет, но, возможно, как другие подходят к дизайну, подобному этому, и что является наиболее "разумным".

Спасибо

Обновление: Добавлен пример кода моего модуля библиотеки ООП, который также использует другие объекты (PGPSimple, SFTP). Дайте мне знать, если вы можете придумать лучший дизайн / реализацию. Еще раз спасибо.

Lib.pm

use Crypt::PGPSimple;
use Net::SFTP;
use File::Copy;
use Log::Log4perl qw(get_logger :levels);
use File::Basename;

my %CONS = (
    RECIPIENT => "ClientName";
    URL       => 'ftp.host.com';
    USER      => 'user';
    PASS      => ''; # use subroutine to obfuscate the password
    PORT      => '22'
    HOME_DIR  => '/Home';
    IN_DIR    => '/Incoming';
    OUT_DIR   => '/Outgoing';
);
my %VARS;

# private member variables
my ($logger);

BEGIN {
    %VARS = (
        IS_PROD     => $L_is_prod ? 1 : 0;
        APPS        => $ENV{'APPS'};
        OUTDIR      => $ENV{'OUTDIR'};
        TIME_ZONE   => $ENV{"TZ"};
    );

    $logger = get_logger("Lib");
}

sub new {
    my ($class, $self) = @_;

    $self = {
        pgp     => _setup_pgp();
        sftp    => undef; # Don't create SFTP connection until we need it
    };

    return bless($self, $class);
}

sub _setup_pgp {
    my $pgp = Crypt::PGPSimple->new();

    $pgp->PgpVersion(6.5.8);
    $pgp->PgpExePath("/path/to/pgp-6.5.8");
    $pgp->PgpKeyPath("/home/username/.pgp"); # Set this based on environment
    $pgp->PublicKey("pubring.pkr");
    $pgp->PrivateKey("secring.skr");
    $pgp->Password(pp());
    $pgp->UserId();
    $pgp->PgpTempDir("/tmp/");
    $pgp->PgpTimeZone();
    $pgp->PgpVerbose(2);

    return $pgp;
}

sub _setup_sftp {
    # Create SFTP connection 
    my $sftp;
    my ($host, $user, $pass);

    $host = $CONS{URL};
    $user = $CONS{USER};
    $pass = $CONS{PASS};

    $sftp = _connect_sftp($host, (user => $user, password => $pass));
    return $sftp;
}

sub encrypt {

    my ($self, $plain_file) = @_;
    my $pgp = $self->{pgp};

    $logger->info("Setting \$pgp->PlainTextFile to $plain_file");
    $pgp->PlainTextFile($plain_file);
    $pgp->PgpFlags("e");

    my $result = $pgp->EncryptFile;
    if($result != 0) {
        $logger->info("Failed to successfully encrypt $plain_file. Error code: " . $pgp->ErrCode() . ", Result: " . $pgp->Result());
    }

    return $result;
}

sub put {

    my $self = shift;
    $self->{sftp} = _setup_sftp() if(!defined $self->{sftp});
    my $local = $self->{pgp}->EncryptedTextFile();
    my $remote = basename($local);
    ...
    $sftp->put($local, $remote)
    ...

}

Ответы [ 3 ]

3 голосов
/ 25 августа 2011

Я склонен использовать ОО, если мне нужно какое-то состояние для каждого экземпляра. Но я думаю, что нет ничего плохого в процедурном подходе, когда «государство» не нужно.

Относительно одной проблемы с соединением: мы (моя компания) используем «сервисный класс» (процедурный), который возвращает подходящее соединение - это полезно, если используются потоки / вилки или если возможно несколько соединений (например, с разные варианты).

Обновление: если вы решите пойти в ОО, я настоятельно рекомендую использовать Moose, если это возможно. Это сэкономит вам много времени, труда и ошибок ... Посмотрите, как работают благословенные ссылки, но используйте Moose или Mouse для своего кода.

2 голосов
/ 25 августа 2011

Разработайте интерфейс в зависимости от того, какой способ будет наиболее полезным для вас, всех, кто будет использовать модуль, и способ, которым вы собираетесь его использовать. Вы даже можете сделать его с двойным интерфейсом сравнительно легко (по крайней мере, если вы не используете Moose; я никогда не создавал модуль с двойным интерфейсом для Moose, но я подозреваю, что Moose будет бороться с вами довольно тяжело, если вы попробуете его) путем неявного создания частного экземпляра, для которого выполняются процедурные вызовы.

Лично я склоняюсь к ООП для всего, что требует многократно используемых данных (состояние, настройки и т. Д.) Для кода, с которым выполняется код, и полу-двойного интерфейса (в частности, процедурного кода, который допускает вызов как MyMod->proc_name в дополнение к MyMod::proc_name), когда каждый вызов будет включать все необходимые данные в качестве параметров.

В этом конкретном случае, я думаю, я бы пошел с прямым интерфейсом OO, с одним экземпляром класса на одно открытое соединение, а затем, возможно, расширил бы его до двойного интерфейса, если большинству приложений, использующих его, требуется только одно соединение (или возможно нет; я предпочитаю вызывать вещи с синтаксисом ОО, а не иметь дело с экспортированными подпрограммами).

2 голосов
/ 24 августа 2011

Если имеет смысл организовать ваши данные и подпрограммы таким образом, взгляните на Moose , который добавляет множество семантических связок ООП в Perl 5, включая наследование.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...