这个类+构造函数定义模式是否过度冗余?

时间:2010-12-24 12:48:26

标签: oop design-patterns

我经常遇到类似这样的模式:

class Person {
    public string firstName, lastName;
    public Person(string firstName, string lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}

这感觉过于多余(我想一次输入“firstName”,而不是三次就足够了......),但我想不出一个合适的选择。有任何想法吗?也许我只是不知道我应该在这里使用的某种设计模式?

编辑 - 我想我需要详细说明一下。我不是问如何使示例代码“更好”,而是“更短”。在当前状态下,所有成员名称出现4次(声明,初始化,构造函数参数),并且感觉相当多余。所以我想知道是否有一种模式(或语义糖)来获得(大致)相同的行为,但是减少了膨胀。
我为最初不清楚而道歉。

编辑 - 戴夫的C#3.0初始化示例非常好,但我仍然希望得到更一般的答案。 :)

编辑 - 我现在意识到某些语言允许更简洁的实现; Java和C#可能没有。

4 个答案:

答案 0 :(得分:4)

这取决于您要完成的工作以及这些特定值是否 在创建对象时由于某种原因而设置。

如果您只希望在构造中设置所持有的值,则必须按照您的方式声明该类:

class Person
{
    public string FirstName { get; private set; }
    public string Surname { get; private set; }

    public Person(string firstName, string surname)
    {
        // properties are read-only so must be set as part of the constructor
        this.FirstName = firstName;
        this.Surname = surname;
    }
}

如果要求在构造上设置属性,那么您还必须像完成一样定义类。但是,您也可以稍后更改这些值。

class Person
{
    public string FirstName { get; set; }
    public string Surname { get; set; }

    public Person(string firstName, string surname)
    {            
        this.FirstName = firstName;
        this.Surname = surname;
    }
}

如果可以随时设置属性,即它们是否可以在创建时设置,那么您不需要将它们作为构造函数的一部分传递。

class Person
{
    public string FirstName { get; set; }
    public string Surname { get; set; }

    public Person()
    {
    }
}

在C#(3及更高版本)中,您仍然可以在创建过程中设置这些属性,但我不确定其他语言可能具有哪些功能可以反映这一点:

var myPerson = new Person
{
    FirstName = "Test",
    Surname = "Test2",
};

示例全部在C#中,但通常应该包含真正的OOP。

答案 1 :(得分:1)

  

我不是问如何使示例代码“更好”,而是“更短”。在当前状态下,所有成员名称出现4次(声明,初始化,构造函数参数),并且感觉相当多余。所以我想知道是否有一种模式(或语义糖)来获得(大致)相同的行为,但是减少膨胀。

我所知道的这里并没有真正的设计模式,但需要多少重复才能与语言有很大不同。

例如,在Scala中,您可以将其定义为案例类,并丢失所有重复:

case class Person(firstName: String, lastName: String)

同样,在Ruby中,您可以使用属性访问器使类定义非常短:

class Person
  attr_accessor :first_name, :last_name
end

这些都不完全等同于你所描述的内容,而是它们是否定义了可变对象或初始化。但这种冗余绝对是语言依赖的。

答案 2 :(得分:1)

一般模式可能是“使用一种优秀的编程语言”。例如,这一行Scala大致相当于您在上面所写的内容:

class Person(var firstName: String, var lastName: String)

您可以在生成的Person.class文件上运行Java反编译器,以查看您必须使用Java编写哪些内容才能获得相同的功能:

public class Person {
    private String firstName, lastName;

    public String getFirstName() {
        return this.firstName;
    }

    public void setFirstName(String paramString) {
        this.firstName = paramString;
    }

    public String getLastName() {
        return this.lastName;
    }

    public void setLastName(String paramString) {
        this.lastName = paramString;
    }

    public Person(String firstName, String lastName) {
        setFirstName(firstName);
        setLastName(lastName);
    }
}

方法名称会略有不同(而不是getFirstNamesetFirstName Scala仅使用firstNamefirstName_=,而后者又被编码为{{1}因为它在Java中是非法的,但意图是一样的。

如果您可以将课程设为firstName_$eq,您也可以自动生成case classequals的正确实施。

在Ruby中,你会写:

hashCode

再次获得与您在Java示例中获得的内容非常相似的内容。 Person = Struct.new(:first_name, :last:name) 实际上会合成一个看起来大致如此的正确类:

Struct.new

答案 3 :(得分:0)

有些语言设计得很冗长,而且通常不允许你修复它。

就类型声明而言,Java强迫你不仅要陈述,而是要重复明显的陈述。如果你愿意使用像Scala这样的语言,那么类型推断可以解决这个问题。

在Javascript中,既没有静态类型也没有类,构造函数只是生成对象的函数,它看起来像这样:

function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}