3

我有一个旧的非常大的 Perl Tk GUI 应用程序,我正在重构为 Tkx。我想把界面分成几个包,这样我就可以以模块化的方式构建应用程序 UI。另外,我想将视图与模型分开,使用控制器在两者之​​间提供接口。

在我看来,设计它的唯一方法是使用两个巨大的全局变量,一个保存模型 ($MODEL),另一个保存对分布在许多包中的小部件 ($UI) 的引用。然后,控制器使用一系列命令将两者连接起来,如下所示:

$UI->{'entry_widget'}->configure(-variable=>\$MODEL->{'entry_value'});
$UI->{'button_widget'}->configure(-command=>sub {$MODEL->{'entry_value'} = "New Value"} );

我的问题是:有没有更好的方法来设计避免使用这两个大的全局变量($UI 和 $MODEL)的应用程序?任何建议都会非常受欢迎。

4

2 回答 2

1

我认为包方法是一种使某些东西全局可用的方法,但不是全局变量。所以像这样的东西会起作用:

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 );
于 2011-11-22T03:13:51.487 回答
1

您不是要避免全局变量,而是要使用方法,即替换$hashref->{data}$model->dataor $self->model->data,其中$modelor$self是传递给信号处理程序/回调/命令的参数(或 Axeman 演示的“单例”),不是您直接访问的哈希

您使用方法来修改$model,因为方法可以拒绝用无意义/不正确的数据更新模型,它们确保您不会尝试用垄断货币付款

您的应用程序将始终创建一个模型变量和一个视图变量,并通过参数传递连接它们(可能通过中介、控制器)

它们不必是 perl 意义上的实际全局变量(Coping with Scoping),它们可以my $variables并且仍然可以按照您现在使用它们的方式(通过闭包)正常工作,并且您避免了http:/的问题/perl.plover.com/varvarname.html,但是您不会从知道他们需要什么样的燃料(柴油或无铅)的智能模型中受益;并且将您的视图连接到您的模型需要更多的输入

另请参阅什么是 Model View Presenter?

于 2011-11-22T09:00:39.880 回答