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

如何以一种优雅的方式初始化具有很多字段的类?

东云
2023-03-14
问题内容

在我的应用程序中,我必须实例化许多不同类型的对象。每种类型都包含一些字段,需要将其添加到包含类型中。我怎样才能优雅地做到这一点?

我当前的初始化步骤如下所示:

public void testRequest() {

        //All these below used classes are generated classes from xsd schema file.

        CheckRequest checkRequest = new CheckRequest();

        Offers offers = new Offers();
        Offer offer = new Offer();
        HotelOnly hotelOnly = new HotelOnly();
        Hotel hotel = new Hotel();
        Hotels hotels = new Hotels();
        Touroperator touroperator = new Touroperator();
        Provider provider = new Provider();
        Rooms rooms = new Rooms();
        Room room = new Room();
        PersonAssignments personAssignments = new PersonAssignments();
        PersonAssignment personAssignment = new PersonAssignment(); 
        Persons persons = new Persons();
        Person person = new Person();
        Amounts amounts = new Amounts();

        offers.getOffer().add(offer);
        offer.setHotelOnly(hotelOnly);

        room.setRoomCode("roomcode");
        rooms.getRoom().add(room);

        hotels.getHotel().add(hotel);
        hotel.setRooms(rooms);

        hotelOnly.setHotels(hotels);

        checkRequest.setOffers(offers);

        // ...and so on and so on
    }

我真的想避免编写这样的代码,因为必须分别实例化每个对象然后在多行代码中初始化每个字段(例如,必须先调用new Offer()然后setHotelOnly(hotelOnly)再调用add(offer))有点麻烦。

我可以使用什么优雅的方法代替我现有的方法?是否Factories可以使用任何“ ”?您有任何参考资料/示例来避免编写这样的代码吗?

我真的对实现干净的代码感兴趣。

内容:

我正在开发一个RestClient用于将发布请求发送到Web服务的应用程序。

API表示为xsd schema文件,我创建了所有对象JAXB

在发送请求之前,我必须实例化许多对象,因为它们彼此之间具有依赖性。 (要约有酒店,旅馆有房间,房间有人…这些是生成的类)

谢谢你的帮助。


问题答案:

您可以使用构造器或构造器模式或构造器模式的变体来解决初始化步骤中字段过多的问题。

我将扩展您的示例,以证明我对这些选项有用的观点。

了解您的示例:

可以说an Offer只是4个字段的容器类:

public class Offer {
    private int price;
    private Date dateOfOffer;
    private double duration;
    private HotelOnly hotelOnly;
    // etc. for as many or as few fields as you need

    public int getPrice() {
        return price;
    }

    public Date getDateOfOffer() {
        return dateOfOffer;
    }

    // etc.
}

如您的示例所示,要使用以下方法来为这些字段设置值:

    public void setHotelOnly(HotelOnly hotelOnly) {
        this.hotelOnly = hotelOnly;
    }

不幸的是,这意味着如果您需要在所有字段中都包含值的报价,则必须做您拥有的一切:

Offers offers = new Offers();
Offer offer = new Offer();
offer.setPrice(price);
offer.setDateOfOffer(date);
offer.setDuration(duration);
offer.setHotelOnly(hotelOnly);
offers.add(offer);

现在让我们看看如何改善这一点。

选项1:构造函数!

除了默认构造函数(默认构造函数当前为Offer())以外的其他构造函数对于初始化类中字段的值很有用。

Offer使用构造函数的版本如下所示:

public class Offer {
    private int price;
    private Date dateOfOffer;
    //etc.

    // CONSTRUCTOR
    public Offer(int price, Date dateOfOffer, double duration, HotelOnly hotelOnly) {
        this.price = price;
        this.dateOfOffer = dateOfOffer;
        //etc.
    }

    // Your getters and/or setters
}

现在,我们可以在一行中对其进行初始化!

Offers offers = new Offers();
Offer offer = new Offer(price, date, duration, hotelOnly);
offers.add(offer);

更好的是,如果您从未使用过offer那一行:offers.add(offer);您甚至不需要将其保存在变量中!

Offers offers = new Offers();
offers.add( new Offer(price, date, duration, hotelOnly) ); // Works the same as above

选项2:构建器模式

一个生成器模式,如果你想有任何的字段默认值的选项很有用。

构建器模式解决的问题是以下凌乱的代码:

public class Offer {
    private int price;
    private Date dateOfOffer;
    // etc.

    // The original constructor. Sets all the fields to the specified values
    public Offer(int price, Date dateOfOffer, double duration, HotelOnly hotelOnly) {
        this.price = price;
        this.dateOfOffer = dateOfOffer;
        // etc.
    }

    // A constructor that uses default values for all of the fields
    public Offer() {
        // Calls the top constructor with default values
        this(100, new Date("10-13-2015"), 14.5, new HotelOnly());
    }

    // A constructor that uses default values for all of the fields except price
    public Offer(int price) {
        // Calls the top constructor with default values, except price
        this(price, new Date("10-13-2015"), 14.5, new HotelOnly());
    }

    // A constructor that uses default values for all of the fields except Date and HotelOnly
    public Offer(Date date, HotelOnly hotelOnly) {
        this(100, date, 14.5, hotelOnly);
    }

    // A bunch more constructors of different combinations of default and specified values

}

看到那会变得多么混乱吗?

Builder模式是,你把另一个类 的内部 类。

public class Offer {
    private int price;
    // etc.

    public Offer(int price, ...) {
        // Same from above
    }

    public static class OfferBuilder {
        private int buildPrice = 100;
        private Date buildDate = new Date("10-13-2015");
        // etc. Initialize all these new "build" fields with default values

        public OfferBuilder setPrice(int price) {
            // Overrides the default value
            this.buildPrice = price;

            // Why this is here will become evident later
            return this;
        }

        public OfferBuilder setDateOfOffer(Date date) {
            this.buildDate = date;
            return this;
        }

        // etc. for each field

        public Offer build() {
            // Builds an offer with whatever values are stored
            return new Offer(price, date, duration, hotelOnly);
        }
    }
}

现在,您不必具有那么多的构造函数,但是仍然能够选择要保留默认值的值以及要初始化的值。

Offers offers = new Offers();
offers.add(new OfferBuilder().setPrice(20).setHotelOnly(hotelOnly).build());
offers.add(new OfferBuilder().setDuration(14.5).setDate(new Date("10-14-2015")).setPrice(200).build());
offers.add(new OfferBuilder().build());

最后的报价只是带有所有默认值的报价。其他是我设置的默认值。

看看如何使事情变得容易吗?

选项3:构建器样式的变化

您还可以通过简单地使当前的setter返回相同的Offer对象来使用构建器模式。除了没有额外的OfferBuilder类外,其他部分完全相同。

警告:如下面的用户WW所述,此选项破坏了JavaBeans-Java容器类的标准编程约定,例如Offer。因此,您不应将其用于专业目的,而应在自己的实践中加以限制。

public class Offer {
    private int price = 100;
    private Date date = new Date("10-13-2015");
    // etc. Initialize with default values

    // Don't make any constructors

    // Have a getter for each field
    public int getPrice() {
        return price;
    }

    // Make your setters return the same object
    public Offer setPrice(int price) {
        // The same structure as in the builder class
        this.price = price;
        return this;
    }

    // etc. for each field

    // No need for OfferBuilder class or build() method
}

您的新初始化代码是

Offers offers = new Offers();
offers.add(new Offer().setPrice(20).setHotelOnly(hotelOnly));
offers.add(new Offer().setDuration(14.5).setDate(new Date("10-14-2015")).setPrice(200));
offers.add(new Offer());

最后的报价只是带有所有默认值的报价。其他是我设置的默认值。

因此,尽管工作量很大,但如果要清理初始化步骤,则需要对其中每个具有字段的类使用以下选项之一。然后使用每个方法附带的初始化方法。

祝好运!是否需要进一步说明?



 类似资料:
  • 1. 前言 通过之前的学习,我们可以熟练掌握 Spring 容器初始化的方法。常用的方法:一种是纯 xml 文件的方式,第二种是使用群体最多的一种,就是 xml 文件搭配类上面的注解,来进行初始化容器。 我们今天讲解一种全新的方法,也是目前最为流行的一种方法。是基于 JavaConfig 的方式来实现。通俗地说也叫基于注解的方式。 疑问导出: 我们学完了那么多种 Spring 的使用,其实完全可以

  • 问题内容: 我的用户表有26列以上,这正常吗?当该用户表引起我注意时,数据库已被标准化为第3级。设计26列是否可以,或者在设计数据库时应该使用其他优化技术吗? 更多:对表进行分区是什么意思? 问题答案: 26列没有什么问题,但是如果很少使用它们,那就不一样了。 而不是使用26列,而是使用更少的列,并使用序列化字符串将它们分组。 将字段更改为文本字段,然后在代码中可以对它们进行反序列化并使用它们。如

  • 问题内容: 我想知道下面的代码是否有意义,因为编译器会警告“空白的最终字段对象可能尚未初始化”。有更好的方法吗? 问题答案: 我将字段定为final,并强制构造函数将值向上传递:

  • 现在我有了一个,它表示在特定时间板上当前的所有块。 我需要数一下一种类型有多少件,比如白车,黑皇后等,但正常的做法会变得太长,而且看起来很难看。我就是这么做的... 必须有一种更优雅的方法来实现这一点,它需要更少的代码行。我的意思是如果有超过6种类型的碎片和2种类型的颜色。我不能一直像这样给switch语句添加大小写,对吧?但我想不出怎样才能让它更优雅。

  • 问题内容: 我需要一个ConnectionFactory类型的实例字段。供应商可以做到: 可以将其缩短为一行,如下所示: 有没有办法使用lambda使其更简洁一些?我试过以下内容,但无法编译: 问题答案: 您上一个代码段中的问题是编译器无法猜测 是实现接口SAM的lambda表达式(似乎您首先错过了表达式的括号,但无论如何)。 您可以做的是强制转换lambda,以告知编译器这实际上是您实现的接口的

  • 问题内容: 我的孩子做了一项家庭作业,用Java编写二十一点。我为他提供了一些帮助,但大部分时间他都是自己完成的,实际上效果还不错。他甚至发现了我在计算手值时没有看到的错误。但是,他还没有解决一个难题,我能想到的每个解决方案都非常复杂,而且远远超出了他将能够利用其仍基本的Java技能轻松编写代码的范围。 王牌。实际上,不仅有一个Ace,还有四个Ace,您可能可以一手拿到所有四个Ace。当有一个或多