Oop 将模型与其表示分离的面向对象方法
假设我们有一个表示硬件配置的对象。为了便于论证,需要一个温度控制器(TempController)。它包含一个属性,即设定点温度 我需要将此配置保存到一个文件中,以便在其他设备中使用。文件格式(FormatA)是一成不变的。我不想让TempController对象知道文件格式。。。这与那个物体无关。因此,我创建了另一个对象“FormatAExporter”,它将TempController转换为所需的输出 一年后,我们制造了一个新的温度控制器,我们称之为“AdvancedTempController”,它不仅有一个设定点,而且还有速率控制,这意味着还有一个或两个以上的属性。还发明了一种新的文件格式来存储这些属性。。。我们称之为FormatB 这两种文件格式都能够表示这两种设备(如果AdvancedTempController缺少设置,则假定它具有合理的默认值) 问题是:如果不使用“isa”或其他“欺骗”方式来确定我拥有的对象类型,FormatBeExporter如何处理这两种情况 我的第一反应是在每个温度控制器中都有一个方法,可以为该类提供客户导出器,例如TempController.getExporter()和AdvancedTempController.getExporter()。这不太支持多种文件格式 脑海中浮现的另一种方法是,在每个温度控制器中都有一个方法,返回属性及其值的列表,然后格式化程序可以决定如何输出这些属性。这是可行的,但这似乎很复杂 更新:在进一步工作后,后一种方法实际上并不奏效。如果您的所有类型都很简单,那么它可能会很简单,但是如果您的属性是对象,那么您最终只会将问题推到一个级别。。。您必须返回一对字符串、对象值,导出器必须知道对象实际是什么才能使用它们。所以它只是把问题推到了另一个层面Oop 将模型与其表示分离的面向对象方法,oop,Oop,假设我们有一个表示硬件配置的对象。为了便于论证,需要一个温度控制器(TempController)。它包含一个属性,即设定点温度 我需要将此配置保存到一个文件中,以便在其他设备中使用。文件格式(FormatA)是一成不变的。我不想让TempController对象知道文件格式。。。这与那个物体无关。因此,我创建了另一个对象“FormatAExporter”,它将TempController转换为所需的输出 一年后,我们制造了一个新的温度控制器,我们称之为“AdvancedTempControll
是否有任何建议来保持这种灵活性?
< P>我有一个“临时控制器”,通过GETStATE方法,返回一个映射(例如在Python中的一个DICT,在JavaScript中的一个对象,C++中的一个STD::MAP或STD::HASMAP等)的属性和当前值——什么是卷绕的?非常简单,它是完全可扩展的,并且与它的用途(显示、序列化和c)完全分离。如果FormatBeExporter使用AdvancedTempController,那么您可以创建一个使TempController符合AdvancedTempController的桥接类。不过,您可能需要向AdvancedTempController添加某种getFormat()函数 例如:FormatBExporter exporterB;
TempController tempController;
AdvancedTempController bridged = TempToAdvancedTempBridge(tempController);
exporterB.export(bridged);
还可以选择使用键到值映射方案。FormatAExporter导出/导入键“设定点”的值。FormatBeExporter导出/导入键“设定点”和“速率控制”的值。这样,旧的FormatAExporter仍然可以读取新的文件格式(它只是忽略“ratecontrol”),FormatBExporter可以读取旧的文件格式(如果缺少“ratecontrol”,则使用默认值)。嗯,这在很大程度上取决于您所谈论的文件格式 如果它们基于键/值组合(包括嵌套的键/值组合,如xml),那么使用某种类型松散的中间内存对象(可以抛出到适当的文件格式编写器中)是一种很好的方法 如果没有,那么就有一个场景,其中有四种对象和文件格式的组合,每个场景都有自定义逻辑。在这种情况下,可能不可能对每个文件格式都有一个单独的表示形式来处理任何一个控制器。换句话说,如果不能通用化文件格式编写器,就不能通用化它
我真的不喜欢控制器有导出器的想法——我只是不喜欢了解存储机制之类的对象(他们可能知道存储的概念,并通过一些DI机制为他们提供了一个特定的实例)。但我认为你同意这一点,原因也差不多相同。在OO模型中,对象方法作为一个集合是控制器。如果使用OO编程,将程序划分为M和V,而不是C更为有用。您可以做的是让TempController负责使用通用的archiver保存自己
class TempController
{
private Temperature _setPoint;
public Temperature SetPoint { get; set;}
public ImportFrom(Archive archive)
{
SetPoint = archive.Read("SetPoint");
}
public ExportTo(Archive archive)
{
archive.Write("SetPoint", SetPoint);
}
}
class AdvancedTempController
{
private Temperature _setPoint;
private Rate _rateControl;
public Temperature SetPoint { get; set;}
public Rate RateControl { get; set;}
public ImportFrom(Archive archive)
{
SetPoint = archive.Read("SetPoint");
RateControl = archive.ReadWithDefault("RateControl", Rate.Zero);
}
public ExportTo(Archive archive)
{
archive.Write("SetPoint", SetPoint);
archive.Write("RateControl", RateControl);
}
}
通过保持这种方式,控制器不关心实际值是如何存储的,但您仍然可以很好地封装对象的内部
现在,您可以定义一个所有归档类都可以实现的抽象归档类
abstract class Archive
{
public abstract object Read(string key);
public abstract object ReadWithDefault(string key, object defaultValue);
public abstract void Write(string key);
}
FormatA归档程序可以用一种方式完成,FormatB归档程序可以用另一种方式完成
class FormatAArchive : Archive
{
public object Read(string key)
{
// read stuff
}
public object ReadWithDefault(string key, object defaultValue)
{
// if store contains key, read stuff
// else return default value
}
public void Write(string key)
{
// write stuff
}
}
class FormatBArchive : Archive
{
public object Read(string key)
{
// read stuff
}
public object ReadWithDefault(string key, object defaultValue)
{
// if store contains key, read stuff
// else return default value
}
public void Write(string key)
{
// write stuff
}
}
您可以添加另一个控制器类型并将其传递给任何格式化程序。您还可以创建另一个格式化程序并将其传递给任何控制器。在C#或其他支持此功能的语言中,您可以执行以下操作:
class TempController {
int SetPoint;
}
class AdvancedTempController : TempController {
int Rate;
}
class FormatAExporter {
void Export(TempController tc) {
Write(tc.SetPoint);
}
}
class FormatBExporter {
void Export(TempController tc) {
if (tc is AdvancedTempController) {
Write((tc as AdvancedTempController).Rate);
}
Write(tc.SetPoint);
}
}
我想这是应用的地方这也使代码更易于测试,因为它更容易模仿合作者。这比我计划的要复杂,但我喜欢它。它提供了返回列表中所有属性的灵活性,但同时保留了整个接口的类型信息。当然,这是短期内最简单的方法。但tou使用的是is和as。现在,您必须每次维护FormatBeExporter以处理所有各种类型。如果走到极端,你会有一大堆“if”语句来找出类型是什么,而这些类型的全部目的就是自己做这类事情。