是否存在可以“终结”对象私有状态的Java方法?

我有一个课程,我想执行以下操作:

  • 创建类的实例
  • 在单独的类中更改对象的私有属性
  • 冻结对象的属性,以便在我完成初始设置后无法修改它们

我知道有一些解决方法,例如不提供任何 setter 方法,只允许在构造函数中设置属性。我可以毫无问题地实现这一点,但它让我想知道是否有一些更简单的方法可以将对象的属性“冻结”到位。我相信Object.freeze()JavaScript 中有一种方法可以做类似的事情。

回答

不,Java 不提供任何此类解冻/冻结功能。

建造者

您可能可以通过“建设者”满足您的需求。这个想法是您定义第二个类来负责生成您的第一个类的实例。这个构建器类具有用于您要调整的所有各种属性的 setter 方法。完成所有设置后,您调用.build()以生成所需类的实例。如果您愿意,那么所需的实例可能是不可变的。

构建器应该从其 setter 返回对自身的引用,以提供方法链。

如果在您的问题域中适用,构建器可以为某些设置设置默认值。

builder 类提供了一些好处:

  • 实现您的目标,即生成一个对象,该对象只有在调整其预期值才能保持不变。
  • 确保有效值。调用程序员可以使用isValid方法验证构建器,然后更正设置。
  • 允许在适当的情况下返回子类,具体取决于您设置的值。

您可以在与 Java 捆绑的 API 中看到此类构建器。

  • Locale.Builder有设置语言、地区、脚本等的方法。您最终会调用Locale.Builder#build以生成一个Locale对象。
  • DateTimeFormatterBuilder有许多设置器,用于对所需日期时间格式化程序的许多方面进行细微控制。调用toFormatter(与build方法相同的想法)以生成DateTimeFormatter.

例子

这是一个构建器的简短示例。

如果需要一个不可变的对象,那么 arecord可能是合适的。在 Java 16+ 中,记录是定义类的一种简短方式,其主要目的是透明且不可变地通信数据。您只需声明其成员字段的类型和名称。编译器隐式地创建默认构造函数、getter、equals&hashCodetoString

public record Employee( UUID id , String name , LocalDate hired ) {}

虽然记录是一种特殊的类,但它仍然是一个类。所以我们可以嵌套另一个类,一个static构建器类。

public record Employee( UUID id , String name , LocalDate hired ) {
    public static class Builder { … }
}

这是整个示例类。

package work.basil.building;

import java.time.LocalDate;
import java.util.Objects;
import java.util.UUID;

public record Employee( UUID id , String name , LocalDate hired ) {
    public static class Builder {
        // ----------- Members
        private UUID id;
        private String name;
        private LocalDate hired;

        // ----------- Constructor
        public Builder () {
            this.id = UUID.randomUUID();
        }

        // ------- Accessors

        public UUID getId () {
            return id;
        }

        public Employee.Builder setId ( UUID id ) {
            this.id = Objects.requireNonNull( id );
            return this;
        }

        public String getName () {
            return name;
        }

        public Employee.Builder setName ( String name ) {
            Objects.requireNonNull( name );
            if ( name.isBlank() ) {
                throw new IllegalStateException( "Name must have some text, cannot be blank. Message # 346624fd-cb97-447a-9f56-e09ccf2e97f3." );
            } else {
                this.name = name;
            }
            return this;
        }

        public LocalDate getHired () {
            return hired;
        }

        public Employee.Builder setHired ( LocalDate hired ) {
            Objects.requireNonNull( hired );
            if ( hired.isAfter( LocalDate.now() ) ) {
                throw new IllegalStateException( "Hired date cannot be after today. Message # 181717b8-e2b0-4b5c-9fd2-ee45a2339b09." );
            } else {
                this.hired = hired;
            }
            return this;
        }

        // -------- Logic
        public boolean isValid () {
            return Objects.nonNull( this.id ) && Objects.nonNull( this.name ) && Objects.nonNull( this.hired );
        }

        public Employee build () {
            if ( this.isValid() ) {
                return new Employee( this.id , this.name , this.hired );
            } else {
                throw new IllegalStateException( "Builder is not valid, so cannot build new object. Message # c0021179-243c-4da5-b265-85208aaaf072" );
            }
        }
    }
}

示例用法。

 List <Employee> employees =
        List.of(
                new Employee.Builder().setName( "Alice" ).setHired( LocalDate.of( 2018 , Month.MARCH, 23) ).build() ,
                new Employee.Builder().setName( "Bob" ).setHired( LocalDate.of( 2014 , Month.JANUARY, 28) ).build() ,
                new Employee.Builder().setName( "Carol" ).setHired( LocalDate.of( 2013 , Month.JUNE, 17) ).build()
        );

跑的时候。

雇员 = [雇员 [id=9736cb4c-1b32-4924-976b-7340f7f2fdc4, 姓名=爱丽丝, 雇用=2018-03-23], 雇员 [id=0ac4ff54-51b6-45c9-bb57-59f6efe4B, 雇用2014-01-28],员工[id=52cc9d03-3846-464a-bbed-49f022175bee,姓名=卡罗尔,受雇=2013-06-17]]

  • 在这种情况下,我认为您在错误的意义上使用了“short of”。在这种情况下,您使用“short of”是说如果您使用反射,您*可以*实现冻结/解冻机制。

以上是是否存在可以“终结”对象私有状态的Java方法?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>