В моем текущем задании я создаю комплект сценариев Perl, которые зависят в большой степени от объектов. (использование Perl bless()
на Хеше для получения максимально близко к OO)
Теперь, из-за отсутствия лучшего способа поместить это, большинство программистов в моей компании не очень умно. Хуже, у них не любят читать документацию и, кажется, есть проблема при понимании чужого кода. Ковбой, кодирующий, является игрой здесь. Каждый раз, когда они встречаются с проблемой и пытаются зафиксировать ее, они предлагают ужасающее решение, которое на самом деле ничего не решает и обычно делает ее хуже.
Это приводит ко мне, откровенно говоря, не доверяя им код, написанный на утином типизированном языке. Как пример, я вижу слишком много проблем с ними, не получая явную ошибку для неправильного использования объектов. Например, если тип A
имеет участника foo
, и они делают что-то как, instance->goo
, они не собираются видеть проблему сразу. Это возвратит пустое/неопределенное значение, и они, вероятно, потратят впустую час, находя причину. Затем закончите тем, что изменили что-то еще, потому что они правильно не определили исходную проблему.
Таким образом, я провожу мозговой штурм для способа сохранить мой язык сценариев (его быстрая разработка является преимуществом), но дайте явное сообщение об ошибке, когда объект не используется правильно. Я понимаю, что с тех пор нет этапа компиляции или статического контроля типов, ошибка должна будет быть во время выполнения. Все хорошо с этим, пока пользователь получает очень явное уведомление, говоря "этот объект, не имеет X"
Как часть моего решения, я не хочу, чтобы это требовалось, что они проверяют, существует ли метод/переменная прежде, чем попытаться использовать его.
Даже при том, что моя работа находится в Perl, я думаю, что это может быть агностиком языка.
Если у вас есть шанс добавить модули для использования, попробуйте Moose. Он предоставляет практически все возможности, которые вы хотели бы иметь в современной среде программирования, и даже больше. Он выполняет проверку типов, отлично наследуется, имеет возможности интроспекции, а с MooseX::Declare - один из самых приятных интерфейсов для классов Perl. Взгляните:
use MooseX::Declare;
class BankAccount {
has 'balance' => ( isa => 'Num', is => 'rw', default => 0 );
method deposit (Num $amount) {
$self->balance( $self->balance + $amount );
}
method withdraw (Num $amount) {
my $current_balance = $self->balance();
( $current_balance >= $amount )
|| confess "Account overdrawn";
$self->balance( $current_balance - $amount );
}
}
class CheckingAccount extends BankAccount {
has 'overdraft_account' => ( isa => 'BankAccount', is => 'rw' );
before withdraw (Num $amount) {
my $overdraft_amount = $amount - $self->balance();
if ( $self->overdraft_account && $overdraft_amount > 0 ) {
$self->overdraft_account->withdraw($overdraft_amount);
$self->deposit($overdraft_amount);
}
}
}
Я сам думаю, что это довольно круто. :) Это слой над объектной системой Perl, так что он работает с тем, что у вас уже есть (в основном).
С Moose вы можете легко создавать подтипы, так что вы можете быть уверены, что ваши данные действительны. Ленивые программисты согласны: так мало нужно сделать, чтобы подтипы работали в Moose, что проще сделать их, чем не делать! (из Cookbook 4)
subtype 'USState'
=> as Str
=> where {
( exists $STATES->{code2state}{ uc($_) }
|| exists $STATES->{state2code}{ uc($_) } );
};
И тада, USState теперь тип, который вы можете использовать! Никакой суеты, никакой суматохи, и всего лишь небольшое количество кода. Он выдаст ошибку, если что-то не так, и все, что нужно сделать потребителям вашего класса, это передать скаляр с этой строкой в нем. Если все в порядке (а так и должно быть... верно? :) ) Они используют его как обычно, и ваш класс защищен от мусора. Как это здорово!
В Moose есть масса потрясающих вещей, подобных этой.
Поверьте мне. Проверьте это. :)
В Perl
требует, чтобы использовал строгие
и предупреждения об использовании
были включены в 100% кода
Вы можете попробуйте сделать почти частные переменные-члены, создав замыкания . Очень хороший пример - раздел «Частные переменные-члены, тип» в http://www.usenix.org/publications/login/1998-10/perl.html . Они не на 100% конфиденциальны, но довольно неочевидны, как получить доступ, если вы действительно не знаете, что делаете (и требуете, чтобы они прочитали ваш код и провели исследование, чтобы узнать, как).
Если вы не хотите использовать замыкания, следующий подход работает несколько хорошо:
Сделайте все переменные-члены вашего объекта (также известные как хеш-ключи объекта в Perl) обернутыми в средства доступа. Есть способы сделать это эффективно, исходя из стандартов кодирования POV. Один из наименее безопасных - Class :: Accessor :: Fast. Я уверен, что у Moose есть способы получше, но я не так хорошо знаком с Moose.
Убедитесь, что фактические переменные-члены «скрыты» в именах по частному соглашению, например $ object -> {'__ private__var1'}
будет переменной-членом, а $ object-> var1 ()
будет средством доступа для получения / установки.
ПРИМЕЧАНИЕ. И последнее, Class :: Accessor :: Fast - это плохо, поскольку его переменные-члены имеют общие имена с аксессорами. Но у вас могут быть очень простые компоновщики, которые работают так же, как Class :: Accessor :: Fast, и создают ключевые значения, такие как $ obj -> {'__ private__foo'} для «foo».
Это не помешает им выстрелить себе в ногу, но БУДЕТ делать это намного сложнее.
В вашем случае, если они используют $ obj-> goo
или $ obj-> goo ()
, они БУДУТ получить ошибку времени выполнения, по крайней мере, в Perl.
Они, конечно, могли бы изо всех сил сделать $ obj -> {'__ private__goo'}
, но если они будут делать гонзо-ковбойское дерьмо из-за чистой лени, последнее - намного больше работы чем правильное выполнение $ obj-> foo ()
.
Вы также можете сканировать кодовую базу, которая обнаруживает строки типа $ object -> {"_
, хотя, судя по вашему описанию, это может не сработать в качестве сдерживающего фактора.
Вы можете использовать Class::InsideOut или Object::InsideOut, которые обеспечивают настоящую конфиденциальность данных. Вместо того чтобы хранить данные в благословенной хэш-ссылке, благословенная скалярная ссылка используется как ключ к лексическим хэшам данных. Короче говоря, если ваши коллеги попробуют $obj->{member}
, они получат ошибку времени выполнения. В $obj
нет ничего, за что они могли бы ухватиться, и нет простого способа получить данные, кроме как через аксессоры.