分类目录归档:程序相关

C,Python,环境配置等

前端控制器

前端控制器

表现层的请求处理机制需要支持每个用户多个请求,我们可以以集中式或分散式的方式管理这些请求。

如果以分散的方式进行管理可能会导致如下的一些问题:

  • 每个请求都有一个共同的操作,分散处理可能会导致代码的重复。
  • 可能会导致视图导航和视图内容的耦合。
  • 分散处理可能会带来更高的维护成本。

如果我们采用集中的方式进行管理,则可以对安全认证、国际化等操作统一处理,同时也可以在一个集中点处理站点的某些操作(如日志记录,站点全局访问控制等),
并且可以在一个地方处理逻辑在多个视图中重复显示。如此我们有了选择前端控制器的理由。

前端控制器建议集中处理所有请求的处理,然而它并没有限制系统中请求处理器的个数,对于不同的服务,完全可以提供不同的处理器。
这与集中式的管理并不矛盾,其实集中只是一种相对的集中,从而达到解决分散式所产生的问题的目的,
任何一种模式只是为解决一些应用场景的特定问题。

运行机制
一个前端控制器其本体包括两部分:一个分发中心(或叫调度处理程序)和一个command(或动作)层次结构。
当一个请求到达服务器,前端控制器接收此请求,从其请求信息中获取足够的内容并决定下一步操作,然后委托给某个command,执行操作。

分发中心可以是一个类或几个类,它没有页面输出,它的作用就是决定最终运行哪一个command。
这里简单点,可以直接根据参数约定,动态识别并执行。
这种简单方法做到了开闭原则,可以在不修改分发中心的前提下添加新的command。

例子
前端控制器在PHP的框架中基本上都会出现,在实现方式上,前端控制器大多采用Apache的url_rewrite模块,
以在.htaccess中重写规则,将所有请求都转发到index.php文件处理。

如PHP的YII框架,Application即YII framework的前端处理器,它是整个请求过程的运行环境。
Application 接收用户的请求并把它分发到合适的控制器作进一步处理。
其一个访问到动作被执行,简单过程如下:

  • 用户访问 Web 服务器,假设其访问地址为index.php?r=post/show,则其入口脚本 index.php 会处理该请求。
  • index.php建立一个应用实例并运行(run方法,在运行前有若干组件加载,初始化操作)。
  • 在应用从一个叫 HTTPRequest 的应用组件获取此次请求的详情。
  • 在urlManager 的组件的帮助下,根据前面获取的请求详情确定用户要请求的控制器和动作,分别对应CController和CInlineAction。
  • 应用建立一个被请求的控制器实例来进一步处理用户请求,控制器确定由它的actionShow 方法来处理 show 动作。
  • 然后它创建并运行和该动作相关的过滤器(CController->runActionWithFilters( )),如果过滤器允许的话,动作被执行,即CController->runAction() ==> CInlineAction->run()。

对于前端控制器,Java体系中的Struts框架以XML配置方式体现,在strut.xml配置动作,在web.xml中配置过滤器。

  • 前端页面提交以“.do”结尾的请求。
  • FilterDispatcher接收请求并调用Action处理该请求。
  • Action处理完毕返回一个逻辑视图。
  • FilterDispatcher根据Action返回逻辑视图创建物理视图
  • 将物理视图返回给页面。

当然我们也可以在一个PHP文件中实现整个前端控制,直接约定命名规范,根据传递进来的参数动态加载处理器,处理方法,视图等。

关于耦合

在做程序设计时我们经常会听到“高内聚,低耦合”,这是我们追求的目标。 其中内聚是指一个模块内各个元素彼此结合的紧密程度, 高内聚是指一个模块或一个类内部各个元素之间关系紧密,争取用最少的元素和方法实现相应的功能; 耦合是指模块之间互相关联程度的度量, 而低耦合是指一个程序中各个模块之间的联系少和相互依赖程度低,一个模块只需要具体实现一个功能。 总的来说,我们所追求的设计是这样的,每个模块职责单一,一个模块只完成一个相对独立的特定子功能,并且和其他模块之间的关系简单(嗯,保持简单), 在不同的应用场景下复用这些模块,从而组成新的系统或大的模块。

在编写代码的过程中,我们应该尽量实现程序的内聚性。内聚性差的程序通常会让人产生这里什么都有,一片杂乱的景象, 特别是那种将类作为若干不同功能函数集的设计。和内聚性差一样,也会让人产生不好情绪还有高耦合。 耦合就是一些代码或一些模块对另一些代码或模块的依赖。而依赖破坏了当初的分块,严重的模块间耦合会让当初的模块化的设想付之一炬。 虽然这种耦合产生的依赖不是很好,但是我们并不能消除耦合。因为正是这种耦合,各种程序模块才能产生互操作。 所以我们只能在允许的范围内尽量减少不必要的耦合。

我们可以将耦合分为以下三类:

  1. 可以接受的耦合
  2. 不建议使用的耦合
  3. 真的不建议使用的耦合

直接看这三个分类真没啥意义,关键是这些分类中所包含的耦合实例。

可以接受的耦合

可用的耦合是指这种耦合会经常存在,而且有时也必须存在,其害处不大。如数据耦合和标记耦合。 何为 数据耦合,看这样一个例子:

function main() {
    output_name('name');
}

function output_name($name) {
    echo $name;
}
main();

这种以函数间传递参数的方式产生的函数是不可避免的,这对程序没有太大的影响。

标记耦合 是指将一个大的数据结构或类传递给另一个模块或类,而该模块只需要这个数据结构的一小部分,或只需要这个类的一个属性值。 以传递为类为例:

class Foo {
    private $_name;

    public function __construct() {
        $this->_name = __CLASS__;
    }

    public function getName() {
        return $this->_name;
    }
}

function output_name(Foo $foo) {
    echo $foo->getName();
}

output_name(new Foo());

其实我们应该是将getName()的输出直接传递给输出函数。 标记函数在一定程序上阻碍了我们对于程序的理解,因为我们需要去了解这个程序到底调用了类中的哪一个方法或使用了数据结构中的哪一个属性。

不建议使用的耦合

不建议使用的耦合是指那种我们会经常见到的不会影响整体的架构,但是有一些坏味道的代码,如控制耦合,时间耦合

控制耦合 是指一个函数传递的某个参数影响另一个函数中所作的控制决定。有时候这种实现只是为了复用一些代码。 如下示例:

function edit($is_add = 0) {
    if ($is_add) {
        //  一些需要添加的字段
    }else{
        //  一些编辑的字段
    }

    //  公共的字段
    //  保存数据
}

以上的示例只是想复用编辑和添加的操作中一些公共的东西,从而引入是否是添加操作的变量。 如果要重构以上代码,可以将一个函数分为三个函数,添加和修改各是一个,公共代码放一个函数。

时间耦合 是指代码中各个元素之间依赖于时间的关系, 以类的public方法调用为例,如果一个方法A在调用时需要先调用另一个方法B,则这里就是时间耦合。 看一个示例:

class File {

    private $_path;

    public function __construct() {

    }

    public function read() {
        echo 'read file from ', $this->_path, '<br />';
    }

    public function setPath($path) {
        $this->_path = $path;
    }
}

$file = new File();
$file->setPath(__FILE__);
$file->read();

以上是一个示例性质的文件类,在读取一个文件的文件内容之前需要先设置这个文件所在的地址。 这种形式的时间耦合应该尽量避免,如果要重构这样的代码,可以将路径作为一个变量传递给构造函数。

真的不建议使用的耦合

这类耦合一旦出现,虽然不会赤地千里,但会严重影响整体的架构和模块间的关联。如公用耦合

公用耦合 通俗的讲,公共耦合就是使用了全局变量。当两个函数或两个模块访问同一个全局变量时,它们就被公用耦合了。 在PHP中一些全局变量$_GET,$_POST等经常会在一些代码中用到,如果有两段代码都使用了这些变量并且修改了同一个值,但是双方互不相知,此时就会出BUG。

领域耦合 指的是在应用的代码中嵌入了领域或商业知识与规则,简单的讲就是将业务规则硬编码到应用中,为一些特定的业务定制应用。 这在我们的开发中会经常出现,一般会通过配置或特定的领域语言减轻系统某些部分因为耦合带来的问题。

以上的各种耦合的定义都来自《高质量程序设计艺术》一书。

TIPI第六章发布

人生在世,如身处荆棘之中!心不动,人不妄动,不动则不伤。如心动,则人妄动,伤其身,痛其骨,于是体会到世间诸般痛苦。

选择在这个宜嫁娶、宜开光、宜安床的日子里,我们将第六章发布了。 没有华丽的出场,只有深夜的辗转,我们在努力。 虽然过程中有一些纷纷扰扰,但是经历了风雨的彩虹会更加美丽。

这次发布更新的主要内容有:

  1. 新增加第六章内存管理
  2. 增加CHM格式的支持
  3. 部分内容调整

TIPI团队

这次发布时我们提供了CHM版本的下载

TIPI入口>>>