【问题标题】:how to reduce the code of constructor overloading如何减少构造函数重载的代码
【发布时间】:2011-03-21 07:21:28
【问题描述】:

在我的一个班级中,我有很多这样的构造函数..

public MyData(int position,String songName,String duration, boolean e) {

    //initialization of above variable like int, string,string and boolean

}

public MyData(String songName, String artistName, String duration,String downloadPath, String songSize, String albumName,String url,String trackId, boolean e) 
{
 //initialization of above variable like String,String,String,String,String,String,String,String and boolean

}

还有一些类似上面的。 现在是调用时间,我只在需要数据时调用该构造函数。但我不认为我的流程很好,所以我需要一些帮助来减少我的代码以及创建良好的流程。 如果有人有一个很好的流程来实现这一点,那么请分享。

提前致谢。

【问题讨论】:

    标签: java constructor overloading


    【解决方案1】:

    假设您正在有效地应用默认值,通常最好的方法是拥有一个“完整”构造函数并让其他构造函数调用它。例如:

    public Foo(String name)
    {
        // Default the description to null
        this(name, null);
    }
    
    public Foo(String name, String description)
    {
        this.name = name;
        this.description = description;
    }
    

    在重载的构造函数方面,你仍然会遇到很多麻烦,但至少这些“额外”构造函数中的每一个都不包含实际代码 - 只是对另一个构造函数的调用。如果可能,将构造函数链接在一起,以便仅在一个地方指定任何特定值的默认值 - 或使用常量。这样你就可以保持一致性。

    另一种选择是使用遵循构建器模式的“参数对象” - 创建另一个类,其唯一目的是保存构造函数参数的数据。这应该是可变的,具有所有不同值的设置器。通常让设置器返回构建器很有用,因此您可以使用:

    FooParameters parameters = new FooParameters()
        .setName("some name")
        .setDescription("some description");
    
    // Either a constructor call at the end, or give FooParameters
    // a build() or create() method
    Foo foo = new Foo(parameters);
    

    如果您要构建的主要类型是不可变类型,这将特别有用 - 这意味着您可以在调用代码中应用条件逻辑来设置某些参数,但不能设置其他参数。 Java 框架本身在ProcessBuilder 中使用了这种方法,尽管我个人并不热衷于它重载方法名称以根据您是否提供参数来返回值或设置值的方式:(

    请注意最终 sn-p 中构造函数调用上方的注释 - 如果您的帮助类仅有助于创建单一类型的对象,您可以给它一个额外的方法(buildcreate、@ 987654326@,任何最合适的)来代替构造函数调用。这允许您以流畅的方式构建整个最终对象。

    构建器模式的 Java 实现中的一个选项是使用嵌套类型,例如

    Foo foo = new Foo.Builder().setName(...).setDescription(...).build();
    

    这避免了另一个类对构建Foo 的实例有用。

    【讨论】:

    • 我通常发现拥有多个构造函数是一种味道。
    • @dty:有时,有时不是。我发现它没有足够强的信号来概括。这在很大程度上取决于您正在编写的课程类型。
    • 确实如此。在工作中,出于性能原因,我们有自定义序列化,因此我们经常有 1 或 2 个公共“业务”构造函数,一个供内部编组器调用的私有构造函数,如果需要,甚至可能还有一个 @VisibleForTesting。但所有这些收缩器很快就会变得混乱,因为通常不是很明显每个收缩器的用途。
    【解决方案2】:

    您可能希望有另一个对象负责通过 builder 模式创建对象。例如,您可以像这样定义一个对象:

    public class SongBuilder {
        private String artistName;
        private String songTitle;
        /* ... everything else ... */
    
        public SongBuilder setArtistName(String name) {
            this.artistName = name;
            return this;
        }
        public SongBuilder setSongTitle(String title) {
            this.songTitle = title;
            return this;
        }
        /* ... everything else ... */
    
        public Song create() {
             return new Song(artistName, songTitle, /* ... everything else ... */);
        }
    }
    

    然后您可以为Song 定义一个构造函数来接收所有数据。要创建Song,您可以编写

     Song s = new SongBuilder().setSongTitle("Still Alive").setArtistName("GLaDOS").create();
    

    这种方法的优点是您可以为所有参数设置合理的默认值,然后只需为您实际使用的参数调用适当的set 函数。它还允许您轻松添加新参数,而无需返回并重写重要代码。

    另外,正如 Jon Skeet 指出的那样,您可以拥有多个相互调用的构造函数。构建器模式相对于这种方法的优势在于,如果您有 n 个不同的参数,则需要编写 2n 种构造器组合,而您只需要一个构建器。

    希望这会有所帮助!

    【讨论】:

    • 一般来说,构建器会放弃 bean 风格的命名约定。例如在 SongBuilder 中,我将使用 title() 而不是 setSongTitle() - 请注意,我删除了“set”位和“song”位,因为我知道我正在制作一首歌曲。这样你最终得到的东西读起来更像 DSL。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-09-27
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 2011-11-21
    • 2015-12-08
    • 1970-01-01
    相关资源
    最近更新 更多