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

Oop 这是+;构造函数定义模式是否过度冗余?,oop,design-patterns,Oop,Design Patterns,我经常遇到类似的模式: class Person { public string firstName, lastName; public Person(string firstName, string lastName) { this.firstName = firstName; this.lastName = lastName; } } 这感觉太多余了(我想输入“firstName”一次,而不是三次就足够了…),但我想不出合适的替代方法

我经常遇到类似的模式:

class Person {
    public string firstName, lastName;
    public Person(string firstName, string lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }
}
这感觉太多余了(我想输入“firstName”一次,而不是三次就足够了…),但我想不出合适的替代方法。有什么想法吗?也许我只是不知道我应该在这里使用什么样的设计模式

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

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


编辑-我现在意识到某些语言允许更少的冗长实现;Java和C#可能不会。

这取决于您试图实现的目标,以及这些特定值是否具有 在创建对象时出于某种原因进行设置

如果您只希望在构造时设置保留的值,则必须按所做的方式声明类:

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

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

据我所知,这里并没有一个真正的设计模式,但这种重复的程度随着语言的不同而有很大的不同

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

case class Person(firstName: String, lastName: String)
类似地,在Ruby中,您可以使用属性访问器使类定义非常简短:

class Person
  attr_accessor :first_name, :last_name
end

这两种方法都不完全等同于您所描述的方法,具体取决于它们是定义可变对象还是初始化。但是这种冗余显然是语言依赖的。

一般模式可能是“使用一种好的编程语言”。例如,这一行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);
    }
}
方法名称将略有不同(Scala使用的不是
getFirstName
setFirstName
而是
firstName
firstName
,后者反过来被编码为
firstName.$eq
,因为这在Java中是非法的),但意图是相同的

如果您可以使类成为一个
case类
,您还将自动生成
equals
hashCode
的正确实现

在Ruby中,您可以编写:

Person = Struct.new(:first_name, :last:name)
然后再次得到与Java示例中得到的内容非常相似的内容
Struct.new
将实际合成一个大致如下所示的适当类:

class Person
  attr_accessor :first_name, :last_name

  def initialize(first_name, last_name)
    self.first_name, self.last_name = first_name, last_name
  end
end
function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

有些语言被设计成冗长的,它们通常不允许您修复它

就类型声明而言,Java迫使您不仅要声明,还要重复显而易见的操作。如果您愿意使用Scala之类的语言,类型推断基本上可以解决这个问题

在Javascript中,您既没有静态类型也没有类,构造函数只是生成对象的函数,它如下所示:

class Person
  attr_accessor :first_name, :last_name

  def initialize(first_name, last_name)
    self.first_name, self.last_name = first_name, last_name
  end
end
function Person(firstName, lastName) {
    this.firstName = firstName;
    this.lastName = lastName;
}

名字和姓氏是公共的吗?这段代码是谁写的:)?就问题而言,这并不重要。我故意让它尽可能简单。+1,对于这句话“但是你也可以让它在以后更改这些值。”