当前位置: 首页 > 面试题库 >

将构建器放在单独的类中(流利的界面)

帅博远
2023-03-14
问题内容
Foo foo = Foo.builder()
    .setColor(red)
    .setName("Fred")
    .setSize(42)
    .build();

因此,我知道有以下“生成器”解决方案可用于在调用方法时创建命名参数。虽然,这似乎只适用于内部静态类作为生成器,还是我错了?我看过一些有关构建器模式的教程,但对于我尝试做的事情,它们似乎真的很复杂。有什么办法可以使Foo类和Builder类保持分离,同时又可以受益于上述代码的命名参数?

下面是一个典型的设置:

public class Foo {
    public static class Builder {
        public Foo build() {
            return new Foo(this);
        }

        public Builder setSize(int size) {
            this.size = size;
            return this;
        }

        public Builder setColor(Color color) {
            this.color = color;
            return this;
        }

        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        // you can set defaults for these here
        private int size;
        private Color color;
        private String name;
    }

    public static Builder builder() {
        return new Builder();
    }

    private Foo(Builder builder) {
        size = builder.size;
        color = builder.color;
        name = builder.name;
    }

    private final int size;
    private final Color color;
    private final String name;
}

问题答案:

使用组成。为了使事情变得更加轻松和整洁,请不要在source(Foo)和builder(Builder)类中复制所有属性。

例如,在Foo类内部Builder而不是每个Foo属性。

简单的代码段:

import java.util.*;

class UserBasicInfo{
    String nickName;
    String birthDate;
    String gender;

    public UserBasicInfo(String name,String date,String gender){
        this.nickName = name;
        this.birthDate = date;
        this.gender = gender;        
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("Name:DOB:Gender:").append(nickName).append(":").append(birthDate).append(":").
        append(gender);
        return sb.toString();
    }
}

class ContactInfo{
    String eMail;
    String mobileHome;
    String mobileWork;

    public ContactInfo(String mail, String homeNo, String mobileOff){
        this.eMail = mail;
        this.mobileHome = homeNo;
        this.mobileWork = mobileOff;
    }    
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("email:mobile(H):mobile(W):").append(eMail).append(":").append(mobileHome).append(":").append(mobileWork);
        return sb.toString();
    }
}
class FaceBookUser {
    String userName;
    UserBasicInfo userInfo;
    ContactInfo contactInfo;

    public FaceBookUser(String uName){
        this.userName = uName;
    }    
    public void setUserBasicInfo(UserBasicInfo info){
        this.userInfo = info;
    }
    public void setContactInfo(ContactInfo info){
        this.contactInfo = info;
    }    
    public String getUserName(){
        return userName;
    }
    public UserBasicInfo getUserBasicInfo(){
        return userInfo;
    }
    public ContactInfo getContactInfo(){
        return contactInfo;
    }

    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("|User|").append(userName).append("|UserInfo|").append(userInfo).append("|ContactInfo|").append(contactInfo);
        return sb.toString();
    }

    static class FaceBookUserBuilder{
        FaceBookUser user;
        public FaceBookUserBuilder(String userName){
            this.user = new FaceBookUser(userName);
        }
        public FaceBookUserBuilder setUserBasicInfo(UserBasicInfo info){
            user.setUserBasicInfo(info);
            return this;
        }
        public FaceBookUserBuilder setContactInfo(ContactInfo info){
            user.setContactInfo(info);
            return this;
        }
        public FaceBookUser build(){
            return user;
        }
    }
}
public class BuilderPattern{
    public static void main(String args[]){
        FaceBookUser fbUser1 = new FaceBookUser.FaceBookUserBuilder("Ravindra").build(); // Mandatory parameters
        UserBasicInfo info = new UserBasicInfo("sunrise","25-May-1975","M");

        // Build User name + Optional Basic Info 
        FaceBookUser fbUser2 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
                                                setUserBasicInfo(info).build();

        // Build User name + Optional Basic Info + Optional Contact Info
        ContactInfo cInfo = new ContactInfo("xxx@xyz.com","1111111111","2222222222");
        FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
                                                setUserBasicInfo(info).
                                                setContactInfo(cInfo).build();

        System.out.println("Facebook user 1:"+fbUser1);
        System.out.println("Facebook user 2:"+fbUser2);
        System.out.println("Facebook user 3:"+fbUser3);
    }
}

输出:

Facebook user 1:|User|Ravindra|UserInfo|null|ContactInfo|null
Facebook user 2:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|null
Facebook user 3:|User|Ravindra|UserInfo|Name:DOB:Gender:sunrise:25-May-1975:M|ContactInfo|email:mobile(H):mobile(W):xxx@xyz.com:1111111111:2222222222

说明:

  1. FaceBookUser 是一个复杂对象,具有以下使用合成的属性:

    String userName;
    

    UserBasicInfo userInfo;
    ContactInfo contactInfo;

  2. FaceBookUserBuilder是静态构建器类,其中包含和builds FaceBookUser

  3. userName是构建FaceBookUser的唯一必需参数

  4. FaceBookUserBuilder建立FaceBookUser通过设置可选参数:UserBasicInfoContactInfo

  5. 本示例说明了FaceBookUsers从Builder构建的具有不同属性的三个不同属性。

    1. fbUser1被构建为仅具有userName属性的FaceBookUser
    2. fbUser2被构建为FaceBookUser,具有userName和UserBasicInfo
    3. fbUser3被构建为FaceBookUser,具有userName,UserBasicInfo和ContactInfo

在此示例中,已使用合成,而不是在Builder类中复制FaceBookUser的所有属性。

编辑:

将所有相关属性分组为逻辑类。在FaceBookUser中定义所有这些类。不必在类中的Builder包含FaceBookUser中再次添加所有这些成员变量Builder

为简单起见,我添加了两个类:UserBasicInfo和ContactInfo。现在,使用其他属性将这个FaceBookUser类爆炸

NewsFeed
Messages
Friends
Albums
Events
Games
Pages
Ads

等等

如果您在Builder和中都复制了所有这些属性FaceBookUser,则代码将变得难以管理。相反,使用的成分FaceBookUserFaceBookUserBuilder本身,你可以简单的构建过程。

添加以上属性后,您将FaceBookUser像往常一样逐步进行构建。

它将是这样的:

FaceBookUser fbUser3 = new FaceBookUser.FaceBookUserBuilder("Ravindra").
                                        setUserBasicInfo(info).
                                        setNewsFeed(newsFeed).
                                        setMessages(messages).
                                        setFriends(friends).
                                        setAlbums(albums).
                                        setEvents(events).
                                        setGames(games).
                                        setAds(ads).build();


 类似资料:
  • 23.4 流利的构建器API 如果您需要构建ApplicationContext层级结构(具有父/子关系的多上下文),或者如果您只想使用“流利的”构建器API,则可以使用SpringApplicationBuilder。 SpringApplicationBuilder允许您将多个方法调用链接在一起,并包含允许您创建层级结构的parent和child方法。 例如: new SpringApplic

  • 我打算从一个Java项目中提取几个类和包,并将它们放入另一个项目中(该项目将有一个可分发的jar)。这并不太难,但当然,进行如此大规模的重构会带来一些后果。也就是说,在原始项目中有许多类是我想要提取的类的子类。实现这种重构的最佳方法是什么?

  • 问题内容: 我只是在学习AsyncTask,并希望将其用作单独的类,而不是子类。 例如, 和main(ui)线程: 谢谢! 问题答案: 使用界面。就像是: 然后在您的UI线程中执行此操作: 在inetloader中,添加: 然后在postExecute()中,执行以下操作:

  • 本文向大家介绍Design patterns 构建器模式/ C#/流利接口,包括了Design patterns 构建器模式/ C#/流利接口的使用技巧和注意事项,需要的朋友参考一下 示例 用法示例:            

  • 我试图使用maven plugin增强来自另一个Jar的实体类,不幸的是,我没有找到正确的方法。 所以我的问题是:为了能够在构建时增强来自外部Jar的类,我需要配置什么?

  • 问题内容: 我继承了包含静态嵌套类的代码,如下所示: 通过阅读SO(例如Java内部类和静态嵌套类),我相信这等效于两个单独文件中的两个单独类: 和 如果这是正确的,那么维护静态嵌套类结构是否有任何优势,还是应该重构? 问题答案: Jorn陈述是正确的,通常按照以下经验法则来体现: 嵌套类应设为私有,这意味着保留托管类的辅助逻辑,仅此而已。如果您不能将它们设为私有,则可能不应嵌套。 例外是,当您定