如何管理类配置并将其传播到更深层次


How to manage classes configuration and propagate it to deeper levels

我有一些类需要交互。每个类都有许多选项,可以对其进行调整以获得一种或另一种行为。

注意:我没有测试代码,因此可能存在一些语法错误)

注意2:我用PHP编写,但我想这个问题对每种OOP语言都有效)

<?php
class Process
{
    protected $element;
    protected $config;
    protected $default_config = array(
        'process_path' => '/bin/command',
        'default_output_path' => '/tmp/',
        'element_conf' => array()
    );
    public function __construct(array $config)
    {
        $this->config = $config;
        $element_config = array_key_exists('element_conf', $this->config) 
            ? $this->config['element_conf'] 
            : array();
        $this->element = new Element($element_config);
    }
    public function run()
    {
        $this->element->behave();
        // ...
    }
    // ...
}
class Element
{
    protected $type;
    protected $config;
    protected $default_config = array(
        'behaviour_type' => 'evil',
        'can_kill_people' => true
    );
    public function __construct(array $config)
    {
        $this->config = array_replace($this->default_config, $config);
        $this->type = $this->config['behaviour'];
    }
    public function behave()
    {
        // ...
    }
    // ....
}
class Config
{
    // get data from config file and makes it available with a static getter/setter
}
-------------------------------
$element_conf = array(
    'can_kill_people' => false
);
$process_conf = array(
    'default_output_path' => Config::get('default_output_path'),
    'element_conf' => $element_conf
);
$pr = new Process($process_conf);
$pr->run();

我想保持尽可能高的封装,所以我避免直接引用Config类的类(配置也可以从其他地方到达)。

我想听听你对的看法

  • 该方法提供了内部类元素)的配置。我想在顶级初始化它的配置(在调用run()方法之前);但我觉得这条路不好走元素的配置取决于流程

  • 为类提供配置的方法。最好像我的代码中那样传递/设置数组配置,或者我应该将每个设置作为构造函数参数传递,还是使用设置器

  • 是否将配置保留在受保护的属性中,作为数组还是将每个相关设置分配给单个受保护/私有属性?(就像我为Element::type做的那样)

  • 管理类配置的常用方法是什么您是否也尝试使用类来存储配置?你喜欢阵列吗?或者直接传递/设置参数/属性?(在我看来,最后一种方法不那么容易维护)。或者更好的是,是否存在专门针对这种情况的设计模式

如果要通过Element对象对流程类进行参数化,则将Element对象作为参数传递,而不是将其参数作为参数传递。这种方法还强调了Process类依赖于Element类,而Element类现在不能从Process构造函数中立即看到。

至于数组配置——在我看来,使用数组很容易编写,但很难实际使用类,你怎么能容易地知道你的类支持什么设置?我宁愿在构造函数中使用单独的参数,也不愿使用具有已定义属性的单独配置类。

只要你把它封装在一个合理的公共接口中,你如何在类内部做事情其实并不重要。您想要做的是保持尽可能多的私有内容,以便在必要时保持更改类内部工作方式的能力,同时保持向后兼容的公共接口。还要记住,当您能够在不破坏向后兼容性的情况下更改受保护的属性和方法时,protected与public基本相同,因为受保护的特性和方法可以由子类使用。

最后一件事是,如果你的类真的有很多参数可以改变它的行为,那么也许你应该考虑将这些不同的行为拆分为新的类是否会更好,这些新的类会扩展基类或实现它的接口(无论什么更适合你的情况)。

没有最好的方法在全局范围内做某事,只有最好的方法来做你想做的事情(无论是否通用)(应用第一个断言:D)

配置默认值

配置项可以是强制性的,也可以不是强制性的,但应该始终具有默认值(因此它可能不是强制性的)。在我看来,有两种方法可以提供默认值:

  1. 声明方式
    安装配置对象时,将提供所有默认值,但如果源不是动态的,则不可能提供动态值
  2. "内联"方式
    当您请求当前值时,您将提供默认值

但是,事实上,您可以使用自己的规则同时使用这两种方法。

使用这些规则,您可以为元素的配置提供一个默认值。但它的当前配置可以作为子配置或其他源提供。。。流程可以使用的

声明性配置

在源代码中,配置是声明性的,这意味着当您开发它时,您知道配置是存在的,并且必须/可以/应该提供配置。因此,使用带有private元素的对象来存储配置值/format或每个配置键使用一个简单的常量并不重要。

在我的框架中,所有配置都作为数组存储在Config类的受保护成员中。这是因为我需要泛型,但我不允许在配置文件中缺少值

OOP只允许OOP

当你使用OOP时,尽可能多地使用它,对象是类的实例,类是声明的,你知道它的内容意味着什么。如果不使用对象,就不能创建通用源。