开发者

Is this class + constructor definition pattern overly redundant?

I often come across a pattern similar to this:

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

This feels overly redundant (I imagine typing "firstName" once, instead of thrice could be enough…), but I can't think of a prop开发者_运维知识库er alternative. Any ideas? Maybe I just don't know about a certain design pattern I should be using here?

Edit - I think I need to elaborate a little. I'm not asking how to make the example code "better", but rather, "shorter". In its current state, all member names appear 4 times (declaration, initialization, constructor arguments), and it feels rather redundant. So I'm wondering if there is a pattern (or semantic sugar) to get (roughly) the same behavior, but with less bloat.

I apologize for being unclear initially.

Edit - Dave's C# 3.0 initialization example is pretty nice, but I'm still hoping for a more general answer. :)

Edit - I realize now that certain languages allow for less verbose implementations; Java and C# might not.


It depends on what you're trying to accomplish and whether those particular values have to be set for some reason when the object is created.

If you only want the values held to be set on construction then you have to declare the class as you have done:

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;
    }
}

If there's some requirement that the properties be set on construction then you also have to define the class as you have done. However you may also make it possible to change those values later.

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

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

If the properties can be set at any time, i.e. it's optional whether they're set on creation, then you don't need to pass them in as part of the constructor.

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

    public Person()
    {
    }
}

In C# (3 and up) you can still set those properties during creation, but I'm not sure what features other languages have that might mirror this:

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

Examples are all in C# but should hold true OOP in general.


The general pattern probably is "use a good programming language". For example, this single line of Scala is roughly equivalent to what you wrote above:

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

You can run a Java decompiler over the generated Person.class file to see what you would have to write in Java to get the same functionality:

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);
    }
}

The method names will be slightly different (instead of getFirstName and setFirstName Scala uses just firstName and firstName_= the latter of which in turn gets encoded as firstName_$eq, since it is illegal in Java), but the intent is the same.

If you can make your class a case class, you will also get automatically generated proper implementations for equals and hashCode as well.

In Ruby, you would write:

Person = Struct.new(:first_name, :last:name)

and again get something fairly similar to what you would get in your Java example. Struct.new will actually synthesize a proper class that looks roughly like this:

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


I'm not asking how to make the example code "better", but rather, "shorter". In its current state, all member names appear 4 times (declaration, initialization, constructor arguments), and it feels rather redundant. So I'm wondering if there is a pattern (or semantic sugar) to get (roughly) the same behavior, but with less bloat.

There isn't really a design pattern here that I know of, but how much of this repetition is needed varies greatly with language.

For instance, in Scala, you could define this as a case class, and lose all the repetition:

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

Similarly, in Ruby, you can make a class definition quite short by using attribute accessors:

class Person
  attr_accessor :first_name, :last_name
end

Neither of these is precisely equivalent to what you've described, with variation on whether they define mutable objects or initialization. But this sort of redundancy is very definitely language-dependent.


Some languages are designed to be verbose, and they usually don't allow you to fix that.

As far as type declarations go, Java forces you to not only state, but to repeat the obvious. Type inference can mostly fix that, if you're willing to use languages like Scala.

In Javascript, where you have neither static types nor classes, constructors are just functions that produce objects and it would look like this:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜