- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
考虑以下类之间的关系:
int main(int, char**) { | class Window { | class Layout { | class Box {
/* Use argc/argv */ | Layout layout; | Box box; | int height,
Window window; | | | max_width;
} | bool print_fps; | public: |
| | Layout(); | public:
| public: | }; | Box (int,int);
| Window (); | | };
| }; | |
main()
我获取了一些应用程序参数(通过配置文件、数据库、CLI 参数)。现在我想将这些值传递给所需的对象。
Window
构造函数
Window
所需的一切,
Layout
和
Box
.然后,
Window
给
Layout
Layout
所需的一切和
Box
.等等。
bool
这样的原语。和
int
事实上,如果我接受它们作为构造函数参数,我会得到上面描述的结果 - 一个很长的类似调用链:
Window(box_height, box_max_width, window_print_fps)
.
Box::height
的类型怎么办至
long
?我需要遍历链中每个类的每一对头/源来更改它。
this->config["box"]["height"]
- 大家都很开心。
Config
)和整个代码库之间的紧密耦合。
int height
至 Box
,那么它需要知道 box 才能正确解析值,对吗? (紧耦合)最佳答案
我非常赞成第二种方法,并编写了一个实现的快速概述。请记住,我并不是说这是最好的解决方案,但是,在我看来这是一个可靠的解决方案。有兴趣听取您的意见和批评。
首先,有一些代表可配置值的小对象。
class ConfigurationParameterBase
{
public:
ConfigurationParameterBase(ConfigurationService* service,
std::string name)
: service_(service), name_(std::move(name)) {
assert(service_);
service_->registerParameter(this);
}
protected:
~ConfigurationParameterBase() {
service_->unregisterParameter(this);
}
public:
std::string name() const { return name_; }
virtual bool trySet(const std::string& s) = 0;
private:
ConfigurationService* service_;
std::string name_;
};
template<typename T>
class ConfigurationParameter : public ConfigurationParameterBase
{
public:
ConfigurationParameter(ConfigurationService* service,
std::string name, std::function<void(T)> updateCallback = {})
: ConfigurationParameterBase(service, std::move(name))
, value_(boost::none)
, updateCallback_(std::move(updateCallback))
{ }
bool isSet() const { return !!value_; }
T get() const { return *value_; }
T get(const T& _default) const { return isSet() ? get() : _default; }
bool trySet(const std::string& s) override {
if(!fromString<T>(s, value_))
return false;
if(updateCallback_)
updateCallback_(*value_);
return true;
}
private:
boost::optional<T> value_;
std::function<void(T)> updateCallback_;
};
ConfigurationService
注册和注销具有给定名称的类。目的。除此之外,它强制派生类实现
trySet
,它将配置值(字符串)读入参数预期的类型。如果成功,则存储该值并调用回调(如果有)。
ConfigurationService
.它负责跟踪当前配置和所有观察者。可以使用
setConfigurationParameter
设置各个选项.在这里,我们可以添加函数来从文件、数据库、网络或其他任何地方读取整个配置。
class ConfigurationService
{
public:
void registerParameter(ConfigurationParameterBase* param) {
// keep track of this observer
params_.insert(param);
// set current configuration value (if one exists)
auto v = values_.find(param->name());
if(v != values_.end())
param->trySet(v->second);
}
void unregisterParameter(ConfigurationParameterBase* param) {
params_.erase(param);
}
void setConfigurationParameter(const std::string& name,
const std::string& value) {
// store setting
values_[name] = value;
// update all 'observers'
for(auto& p : params_) {
if(p->name() == name) {
if(!p->trySet(value))
reportInvalidParameter(name, value);
}
}
}
void readConfigurationFromFile(const std::string& filename) {
// read your file ...
// and for each entry (n,v) do
// setConfigurationParameter(n, v);
}
protected:
void reportInvalidParameter(const std::string& name,
const std::string& value) {
// report whatever ...
}
private:
std::set<ConfigurationParameterBase*> params_;
std::map<std::string, std::string> values_;
};
T
)都被替换为成员
ConfigurationParameter<T>
并在构造函数中使用相应的配置名称进行初始化,以及 - 可选 - 更新回调。然后类可以像使用普通类成员一样使用这些值(例如
fillRect(backgroundColor_.get())
),并且只要值发生变化就会调用回调。注意这些回调是如何直接映射到类的标准 setter 方法的。
class Button
{
public:
Button(ConfigurationService* service)
: fontSize_(service, "app.fontSize",
[this](int v) { setFontSize(v); })
, buttonText_(service, "app.button.text") {
// ...
}
void setFontSize(int size) { /* ... */ }
private:
ConfigurationParameter<int> fontSize_;
ConfigurationParameter<std::string> buttonText_;
};
class Window
{
public:
Window(ConfigurationService* service)
: backgroundColor_(service, "app.mainWindow.bgColor",
[this](Color c){ setBackgroundColor(c); })
, fontSize_(service, "app.fontSize") {
// ...
button_ = std::make_unique<Button>(service);
}
void setBackgroundColor(Color color) { /* ... */ }
private:
ConfigurationParameter<Color> backgroundColor_;
ConfigurationParameter<int> fontSize_;
std::unique_ptr<Button> button_;
};
main
中)。创建
ConfigurationService
的实例然后创建可以访问它的所有内容。对于上述实现,重要的是
service
比所有观察者的生命周期都长,但是这可以很容易地改变。
int main()
{
ConfigurationService service;
auto win = std::make_unique<Window>(&service);
service.readConfigurationFromFile("config.ini");
// go into main loop
// change configuration(s) whenever you need
service.setConfigurationParameter("app.fontSize", "12");
}
Window
不需要了解Button
的配置。 . ConfigurationService
,但是可以通过接口(interface)轻松实现这一点,从而使实际实现可互换。 fromString
模板,但如果您想从文本文件中解析配置,无论如何都需要这样做。 loadConfigurationFromDatabase
)添加到 ConfigurationService
,这样做。 ConfigurationService
添加相应的方法并且可以在程序退出时将以编程方式更改的配置写回文件或数据库。 ConfigurationParameter
成员)。这可以通过提供相应的强制转换运算符 ( operator T() const
) 来进一步改进。 ConfigurationService
实例必须传递给所有需要注册的类。这可以使用全局或静态实例(例如作为单例)来规避,尽管我不确定这是否更好。 关于c++ - 如何使深度中的对象易于配置 "from the top"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45998746/
我的一位教授给了我们一些考试练习题,其中一个问题类似于下面(伪代码): a.setColor(blue); b.setColor(red); a = b; b.setColor(purple); b
我似乎经常使用这个测试 if( object && object !== "null" && object !== "undefined" ){ doSomething(); } 在对象上,我
C# Object/object 是值类型还是引用类型? 我检查过它们可以保留引用,但是这个引用不能用于更改对象。 using System; class MyClass { public s
我在通过 AJAX 发送 json 时遇到问题。 var data = [{"name": "Will", "surname": "Smith", "age": "40"},{"name": "Wil
当我尝试访问我的 View 中的对象 {{result}} 时(我从 Express js 服务器发送该对象),它只显示 [object][object]有谁知道如何获取 JSON 格式的值吗? 这是
我有不同类型的数据(可能是字符串、整数......)。这是一个简单的例子: public static void main(String[] args) { before("one"); }
嗨,我是 json 和 javascript 的新手。 我在这个网站找到了使用json数据作为表格的方法。 我很好奇为什么当我尝试使用 json 数据作为表时,我得到 [Object,Object]
已关闭。此问题需要 debugging details 。目前不接受答案。 编辑问题以包含 desired behavior, a specific problem or error, and the
我听别人说 null == object 比 object == null check 例如: void m1(Object obj ) { if(null == obj) // Is thi
Match 对象 提供了对正则表达式匹配的只读属性的访问。 说明 Match 对象只能通过 RegExp 对象的 Execute 方法来创建,该方法实际上返回了 Match 对象的集合。所有的
Class 对象 使用 Class 语句创建的对象。提供了对类的各种事件的访问。 说明 不允许显式地将一个变量声明为 Class 类型。在 VBScript 的上下文中,“类对象”一词指的是用
Folder 对象 提供对文件夹所有属性的访问。 说明 以下代码举例说明如何获得 Folder 对象并查看它的属性: Function ShowDateCreated(f
File 对象 提供对文件的所有属性的访问。 说明 以下代码举例说明如何获得一个 File 对象并查看它的属性: Function ShowDateCreated(fil
Drive 对象 提供对磁盘驱动器或网络共享的属性的访问。 说明 以下代码举例说明如何使用 Drive 对象访问驱动器的属性: Function ShowFreeSpac
FileSystemObject 对象 提供对计算机文件系统的访问。 说明 以下代码举例说明如何使用 FileSystemObject 对象返回一个 TextStream 对象,此对象可以被读
我是 javascript OOP 的新手,我认为这是一个相对基本的问题,但我无法通过搜索网络找到任何帮助。我是否遗漏了什么,或者我只是以错误的方式解决了这个问题? 这是我的示例代码: functio
我可以很容易地创造出很多不同的对象。例如像这样: var myObject = { myFunction: function () { return ""; } };
function Person(fname, lname) { this.fname = fname, this.lname = lname, this.getName = function()
任何人都可以向我解释为什么下面的代码给出 (object, Object) 吗? (console.log(dope) 给出了它应该的内容,但在 JSON.stringify 和 JSON.parse
我正在尝试完成散点图 exercise来自免费代码营。然而,我现在只自己学习了 d3 几个小时,在遵循 lynda.com 的教程后,我一直在尝试确定如何在工具提示中显示特定数据。 This code
我是一名优秀的程序员,十分优秀!