使用访问者:好还是坏?

时间:2010-09-10 07:37:01

标签: design-patterns oop

我遇到了一个设计问题我可以使用一些建议。假设我们需要(原始......)员工在我们的新应用程序中。我通常会做的是这样的事情:

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上吸气剂的必要性,因此是更好的数据封装形式,但它似乎有点臃肿且过于复杂。你对这件事有什么看法?我是否遗漏或误解了文章中的内容?您对使用getter(和setter)的一般看法是什么?

这个小实验让我倾向于使用存取方法。也许你可以改变主意: - )

2 个答案:

答案 0 :(得分:3)

我认为访问者(getter和setter)要好得多,至少在你的例子中如此。 我认为在这里使用DTO模式没有任何优势,最重要的是,代码变得不可读。编写优秀软件的关键之一就是简单性:代码越简单,可读性越强,可维护性越强。 一般来说,应该在解决问题时使用模式。因此,您首先需要检测问题,然后使用最简单的模式解决问题,从而解决问题。 使用DTO模式的选择应该得到它解决特定问题的事实的支持。

答案 1 :(得分:1)

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

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

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

这比指令列表更容易阅读,其主要目的是从对象中提取数据并将其放入另一个对象。我一眼就知道这段代码将时间表显示为一个表格。