如何重构这个C#代码?

时间:2012-11-17 01:02:16

标签: c# refactoring

我正在研究遗留代码,我看过很多这样的代码:

public class Person
{
    public Person(PersonData data)
    {
        this.Name = data.Name;
        this.Gender = data.Gender ;
    }

    public String Name { get; private set;}
    public String Gender { get; private set;}
}

public class PersonData
{
    public String Name;
    public String Gender;
}

public static Person ReadPerson(Reader reader)
{
    PersonData data = new PersonData;
    data.Name = reader.ReadString();
    data.Gender = reader.ReadString();

    Person p = new Person(data);
    return p;
}

PersonData类用于在其构造函数中设置Person类中的私有字段。除此之外,PersonData类引入了冗余代码,正如您所看到的,现在您在Person和PersonData类中都有Name和Sex。

在我的观点中,这种设计不能扩展:现在我有一个新的字段“Age”来阅读,我必须在两个不同的地方添加“Age”属性。

这是一个有效的设计选择(假设我在遗留代码中看到很多代码)吗? 我怎么能重构这个?

修改

这两个类是真实代码的简化版。所以请原谅使用字符串而不是枚举用于性别。

在真实代码中,PersonData有超过10个字段,因此是Person类。

5 个答案:

答案 0 :(得分:3)

在使用Constructor Injection时,使用参数对象是一种有效的方法,并且在构造函数中开始获取大量参数 - 但是当您拥有的参数较少时,这是不必要的。

这是一个建议:

public class Person
{
    public Person(string name, string sex)
    {
        _name = name;
        _sex = sex;
    }

    public string Name { get {return _name; }}
    public string Sex { get {return _sex; }}

    private readonly string _name, _sex;
}

这使得课程immutable

答案 1 :(得分:1)

如果它是某种面向外部的对象(与您的情况似乎不同的数据传输对象),您可以考虑使用流畅的接口来构建它们,它不会减少类的数量,但会让您构造对象以更加花哨的方式,更好地控制所需要的和可选的。

如果感兴趣,请参阅标有fluent-interface的帖子。即Conditional Builder Method Chaining Fluent Interface

var person = PersonBuilder
  .CreatePerson()
    .Named(reader.ReadString())
    .Sex(reader.ReadString())
    .Build()

答案 2 :(得分:0)

一种方法是代替

public String Name { get; private set;}
public String Sex { get; private set;}

公开PersonData

类型的属性
public class Person
{
    public PersonData PersonData { get; }
}

另外,您可以查看从Person中获取PersonData

答案 3 :(得分:0)

摆脱PersonData并将Reader提供给构造函数:

public sealed class Person
{
    public Person(Reader reader)
    {
        this.Name = reader.ReadString();
        this.Sex = reader.ReadString();
    }

    public string Name { get; private set; }

    public string Sex { get; private set; }
}

答案 4 :(得分:0)

一般来说,我会回到你正在建模的现实世界(或商业:)系统。如果班级匹配那个世界中的某些东西,那就没关系了。如果这个类纯粹是编程系统的一个工件而且看起来没必要,那我就把它扔掉。使用“data”类还可以隐藏使用显式参数捕获的各种问题。例如,当您添加“年龄”时,您将如何检测到所有案例都被发现?如果将其添加为构造函数参数,则每个丢失的案例都会出错。