我有一个旧的非常大的Perl Tk GUI应用程序,我正在将其重构为Tkx。我想把接口分成几个包,这样我就可以以模块化的方式构建应用程序UI。另外,我想保持视图与模型的分离,使用控制器提供两者之间的接口。
在我看来,设计它的唯一方法是使用两个巨大的全局变量,一个保存模型($ model),另一个保存对分布在许多包中的小部件($UI)的引用。然后,Controller使用如下一系列命令将两者连接起来:
$UI->{'entry_widget'}->configure(-variable=>$MODEL->{'entry_value'});
$UI->{'button_widget'}->configure(-command=>sub {$MODEL->{'entry_value'} = "New Value"} );
我的问题是:有没有更好的方法来设计应用程序,避免使用这两个大的全局变量($UI和$MODEL)?欢迎提出任何建议。
我认为包方法是一种使全局可用的方法,但不是全局变量。所以像这样可以:
package MVC;
use strict;
use warnings;
use Scalar::Util qw<refaddr>;
my %MVCs;
sub _domain {
my ( $domain_name, $ref, $value ) = @_;
my $r = $MVCs{ $key }{ $domain_name };
return unless $$r or ref( $value );
if ( ref $value ) {
$$r = $value;
}
return $$r;
}
sub model { shift; return _domain( 'model', @_ ); }
sub controller { shift; return _domain( 'controller', @_ ); }
sub view { shift; return _domain( 'view', @_ ); }
所以在包外,你只需要调用这个:
my $controller = MVC->controller( $self );
获取与对象关联的控制器。
您甚至可以在访问器中添加一些导出逻辑,如:
unless ( $ref->can( $domain_name )) {
not strict 'refs';
*{ ref( $ref ) . "::$domain_name" }
= sub { _domain( $domain_name, $ref ) }
;
}
你可以这样写:
$self->view->view_method( @args );
您不希望避免全局变量,您希望使用方法,即用$model->data
或$self->model->data
替换$hashref->{data}
,其中$model
或$self
是传递给信号处理程序/回调/命令的参数(或Axeman演示的"单例"),而不是您直接访问的哈希值
你使用方法来修改$model
,因为方法可以拒绝用无意义/不正确的数据更新模型,它们确保你没有试图用垄断货币支付
你的应用程序总是会创建一个模型变量和一个视图变量,并通过参数传递将它们连接起来(可能通过中介,控制器)
它们不必是perl意义上的实际全局变量(处理作用域),它们可以是my $variables
并且仍然可以很好地工作,就像你现在使用它们的方式(通过闭包),并且你避免了http://perl.plover.com/varvarname.html的问题,但是你没有得到智能模型的好处,知道他们需要什么样的燃料(柴油或无铅);将视图连接到模型需要更多类型
参见什么是模型视图演示器?