面向对象的方式将模型与其表示分开

Chr*_*uin 6 oop

假设我们有一个对象代表一块硬件的配置.为了论证,温度控制器(TempController).它包含一个属性,即设定点温度.

我需要将此配置保存到文件中以便在其他设备中使用.文件格式(FormatA)是一成不变的.我不希望TempController对象知道文件格式......它与该对象无关.所以我创建了另一个对象"FormatAExporter",它将TempController转换为所需的输出.

一年后,我们制作了一个新的温度控制器,我们称之为"AdvancedTempController",它不仅具有设定值,而且还具有速率控制,这意味着还有一两个属性.还发明了一种新的文件格式来存储这些属性......我们称之为FormatB.

两种文件格式都能够表示两种设备(如果缺少设置,则假设AdvancedTempController具有合理的默认值).

所以这就是问题所在:不使用'isa'或其他"作弊"方式来确定我拥有的对象类型,FormatBExporter如何处理这两种情况?

我的第一直觉是在每个温度控制器中都有一个方法,可以为该类提供客户导出器,例如TempController.getExporter()和AdvancedTempController.getExporter().这不能很好地支持多种文件格式.

我想到的唯一另一种方法是在每个温度控制器中有一个方法,它返回一个属性列表及其值,然后格式化程序可以决定如何输出它们.它有用,但这看起来很复杂.

更新:进一步的工作,后一种方法并没有真正奏效.如果你的所有类型都很简单,但是如果你的属性是对象,那么你最终只是将问题推到一个级别......你被迫返回一对String,Object值,导出器必须知道什么对象实际上是要利用它们.所以它只是把问题推到了另一个层面.

对于我如何保持这种灵活性有什么建议吗?

jop*_*jop 4

您可以做的是让 TempController 负责使用通用存档器来持久保存自身。

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

通过保持这种方式,控制器不关心实际值如何存储,但您仍然可以很好地封装对象的内部结构。

现在您可以定义一个所有存档类都可以实现的抽象 Archive 类。

abstract class Archive
{
    public abstract object Read(string key);
    public abstract object ReadWithDefault(string key, object defaultValue);
    public abstract void Write(string key);
}
Run Code Online (Sandbox Code Playgroud)

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
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以添加另一个控制器类型并将其传递给任何格式化程序。您还可以创建另一个格式化程序并将其传递给任何控制器。