使用访问器:好还是不好?

4

我有一个设计问题,希望能得到一些建议。假设我们的新应用程序需要(多么原创啊...)员工信息。通常我会像这样做:

public interface IEmployee
{
    string EmployeeId { get; }
    string Name { get; }
    void Update(string newName, ...);
    ...
}

public class Employee : IEmployee
{
    public Employee(string id, string name, ...)
    {

    }
    ...
}

从数据源获取员工信息

public class SqlEmployeeRepository : IEmployeeRepository
{
    ...

    public IEmployee GetEmployee(string id)
    {
        ...
        IEmployee employee = new Employee(id, name, ...);
        return employee
    }

    public IEmployee SaveEmployee(IEmployee employee)
    {
        // Execute SQL command.
    }
}

可视化将看起来像这样:

TextBox nameTextBox = new TextBox();
...
nameTextBox.Text = employee.Name;

保存的样子如下:

string name = nameTextBox.Text;
employee.Update(name, ...);
myEmployeeRepository.Save(employee);

到目前为止,一切都很好。但是,当我看到thisthis这两篇文章时,我开始想象如果没有getter,该应用程序(静态和动态)会是什么样子,因此我尝试使用第二篇文章中描述的技术来实现上述应用程序,不使用getter。我得到了以下代码:
public interface IEmployee
{
    public interface Importer
    {
        string ProvideId();
        string ProvideName();
        ...
    }

    public interface Exporter
    {
        void AddId();
        void AddName();
        ...
    }

    void Export(IExporter exporter)
    ...
}

public class Employee : IEmployee
{
    private string _id;

    private string _name;

    public Employee(IEmployee.Importer importer)
    {
        _id = importer.ProvideId();
        _name = importer.ProvideName();
        ...
    }

    public void Export(IEmployee.Exporter exporter)
    {
        exporter.AddId(_id);
        exporter.AddName(_name);
        ...
    }
}

然后仓库变成:
public class SqlEmployeeExporter : IEmployee.Exporter
{
    ...
    public void Save() { ... }
}

public class SqlEmployeeRepository : IEmployeeRepository
{
    ...

    public IEmployee GetEmployee(string id)
    {
        IEmployee.Importer importer = new SqlEmployeeImporter(id);
        IEmployee employee = new Employee(importer);
        return employee
    }

    public IEmployee SaveEmployee(IEmployee employee)
    {
        SqlEmployeeExporter exporter = new SqlEmployeeExporter();
        employee.Export(exporter);
        exporter.Save();
    }
}

可视化变成了:

EmployeeNameTextBoxExporter exporter = new EmployeeNameTextBoxExporter();
employee.Export(exporter);
exporter.Render();

关于保存操作,也有类似的实现方式。

虽然后一种实现方式去掉了对 Employee 的 getters 的需求,因此是更好的数据封装形式,但它似乎有点臃肿和过于复杂。您对此有何看法?我是否在文章中漏掉或误解了什么?您对使用 getters(和 setters)的一般看法是什么?

这个小实验让我倾向于暂时使用访问器方法。也许您可以改变我的想法 :-)


看起来你的 Exporter 对象实际上是一个 DTO:http://en.wikipedia.org/wiki/Data_transfer_object - Sjoerd
你所提到的文章相当有争议(尤其是标题),应该持保留态度 :-) 一般来说,人们认为并不是反对 getter/setter 的使用,而是反对暴露_不必要_的 getter/setter。这个问题已经在 SO 上讨论过了,例如:https://dev59.com/T3E85IYBdhLWcg3wgDpI,https://dev59.com/3HRB5IYBdhLWcg3wpYio。 - Péter Török
2个回答

3
我认为访问器(getter和setter)在你的示例中要好得多。 我不认为在这里使用DTO模式有任何优势,最重要的是,代码变得难以阅读。编写良好软件的关键之一是简单性:代码越简单,可读性和可维护性就越高。 通常情况下,模式应该用于解决问题。因此,您首先需要检测问题,然后应用最简单的模式来解决问题。 使用DTO模式的选择应该基于它是否解决了特定问题。

完全同意。我认为属性看起来更加熟悉。可读性规则 :) - dmitko

1

看一个简短的代码片段自然会显得简单,并不需要这样的封装。随着程序规模的增长,我可以看到这种方法在维护期间节省时间。我没有太多使用这种方法的经验,所以我无法给出明确的答案,但我认为它可以提供足够的好处值得尝试和测量结果。

为了可读性,我认为这种方法比getter/setter有一些优势。假设您想将员工的工作计划显示为表格。使用“构建器”方法,高级别代码基本保持不变:

ScheduleDisplay display = new TableScheduleDisplay();
employee.Export(display);
display.Render();

这比一长串指令容易阅读多了,因为它的主要目的是从一个对象中提取数据并将其放入另一个对象中。我一眼就知道这段代码将日程表显示为一个表格。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接