在不破坏封装的情况下公开对象数据

本文关键字:对象 数据 情况下 封装 | 更新日期: 2023-09-27 18:22:30

良好的面向对象设计表明对象不应该公开其内部。在这种情况下,显示数据的最佳方式是什么?

例如,在控制台应用程序中调用DoSomethingToData后,如何显示数据字段?

public class Foo {
    string data;
    public void DoSomethingToData(string someParam) {
        .....
    }
}
class Program {
    static void Main(string[] items) {
        var foo = new Foo();
        foo.DoSomethingToData("blah");
        ..... // how do we write data field to console without breaking encapsulation?
    }
}

更新:我认为维护封装的最好方法是使用观察者模式(事件),但没有人提到它。这是比公开属性或方法结果更好的解决方案吗?

在不破坏封装的情况下公开对象数据

这取决于;

  • 如果该值仅与该方法相关,则将其作为该方法的返回值
  • 如果值与对象相关,则通过属性公开它

我怀疑是后者,所以:

 public string Data { get { return data; } }

它只是一个访问器——例如,相当于java中的getData()。这不是公开字段,但最终您的对象应该向信息公开一些API。这并不是一个完全的秘密。

您可以添加ToString方法(或类似方法),以提供适合记录到控制台的字符串表示。

public class Foo
{
    private string data;
    public void DoSomethingToData(string someParam) {
        .....
    }
    public override string ToString()
    {
        return string.Format("Foo data: {0}", data);
    }
}

这让类的客户端清楚地知道,除了调试/日志记录之外,数据字段的内容不打算在类之外使用。


或者,您可以私有化一个允许直接(只读)访问私有字符串的公共getter属性,但请注意,以这种方式提供这样的属性可能会导致该类的客户端将Data字段用于除日志记录之外的更通用目的。

public string Data { get { return data; } }

最后一个选项是使用自动实现的属性并完全删除字段(自动实现的特性将使用自己的后备字段):

public string Data { get; private set; }

一些常见的方法:

  • 为实例的某些通用文本表示重写ToString()(这可能反映了您想要的内部数据,也可能不反映,取决于细节和上下文)
  • 如果根据某些特定的内部数据进行计算,则公开方法
  • 公开getter以不可变地公开内部数据
  • 如果只需要在调试时检查内部行为,请对类实例使用调试器和"监视"

在Foo类中生成属性

    public string Data
    {
        get{return data;}
        set{data = value;}
    }

将数据视为属性。数据是一种不需要按照分配方式存储的属性。属性可以通过从/到其后备存储的转换来获得/存储。通过对私有存储变量内部结构的转换组合,可以获得多个属性。

private double booTheBackingStore;
private int myfactor;
public String data{
  get{
    return "<data>"+booTheBackingStore*booTheBackingStore+"</data>";
  }
  set{
    String boo = parselTheXml(value);
    double booger;
    Double.tryParse(boo, out booger);
    booTheBackingStore = Math.sqrt(booger);
  }
}

public double dada{
  get{
    return exoTransform(booTheBackingStore, myfactor);
  }
  set{
    booTheBackingStore = endoTransform(value, myfactor);
  }
}

更多信息:

假设您的类是一个网页视图,它具有编辑、浏览、插入和删除模式。对于这些模式中的每一种,视图都必须重新实例化/重新排列小部件。此外,您还必须重新应用样式。

从MVP的角度来看,您需要将您的演示与您的视图解耦。视图需要从公共属性的角度来展示自己。因此,set/get模式属性将封装需要在UI上执行的所有内部。演示者不应该在意视图的排列方式。并且视图不应该有任何过程或数据控制逻辑。

公共属性是促进封装的重要部分,以便只公开视图和演示者之间的契约。

一个健壮的UI设计将有一个服务器端状态机,它与客户端状态机通信,客户端状态机又对表示代理进行排序,而表示代理又要求展示UI视图属性。您的服务器根本不应该直接访问客户端视图。你的客户端状态机也不应该。您的演示者受客户端状态的指导,对UI视图提出要求。演示者只是发出对EDIT模式的需求。它不会干涉UI视图如何实现编辑模式。UI视图不应维护UI的状态。

这种解耦是为了便于单元测试,最重要的是,便于组件的模块化交换。这样,在你将浏览器UI换成移动UI后,你的演示顺序也会同样有效。由于移动UI将实现不同于浏览器UI的各种模式。或者桌面UI。

您需要进一步了解基于组件的设计和"封装"的概念。