나는 일반적으로 다음과 같은 패턴을 사용하려면
- 당신은 당신이 필요로 할 때마다
underlying
값에 액세스 할 수 있습니다
- 방지 패턴이 생성자에 일치 은이 아니며
case class
을 사용하여 실제로 개체가 생성되지 않도록하여 런타임 값이로 유지됩니다.(또는 기본 값이 무엇이든간에)
- 컴패니언 개체를 사용하여 스마트 생성자를 만들어 입력 유효성을 검사하고 사용자가
new
을 사용할 필요가 없도록 값을 구성 할 때보다 깨끗한 인터페이스를 제공 할 수 있습니다. 아래의 스마트 생성자의
예 -
final class ProductId(val underlying: String) extends AnyVal
object ProductId {
def apply(s: String): Result = {
if (s.isEmpty) {
new Failure("ProductId cannot be empty!")
} else {
new Success(new ProductId(s))
}
}
sealed trait Result
final case class Success(productId: ProductId) extends Result
final case class Failure(message: String) extends Result
}
당신이 사용자 가 스마트 생성자를 사용해야하는지 확인하려면, 비공개로 당신의 가치 클래스의 생성자를 표시 -
final class ProductId private (val underlying: String) extends AnyVal
실수로 ProductId
의 인스턴스를 할당하지 않으려면 바이트 코드 -
을 확인할 수 있습니다. 런타임에
ProductId
가
String
로 나타낼 수 있도록 363,210
scala> :paste
class Test {
def testProductId = new ProductId("foo")
def testSmartCtor = ProductId("bar") match {
case ProductId.Success(productId) => productId
case ProductId.Failure(message) => throw new AssertionError(message)
}
}
// Ctrl+D
:javap -c ProductId$
// Skipping to the apply() method
public ProductId$Result apply(java.lang.String);
Code:
0: aload_1
1: invokevirtual #20 // Method java/lang/String.isEmpty:()Z
4: ifeq 19
7: new #22 // class ProductId$Failure
10: dup
11: ldc #24 // String ProductId cannot be empty!
13: invokespecial #27 // Method ProductId$Failure."<init>":(Ljava/lang/String;)V
16: goto 27
19: new #29 // class ProductId$Success
22: dup
23: aload_1
24: invokespecial #30 // Method ProductId$Success."<init>":(Ljava/lang/String;)V
27: areturn
는, 바이트 코드에는 new ProductId
언급이 없습니다.
제네릭 (예 : 옵션, 둘 중 하나)을 사용하는 클래스에서 값 클래스를 래핑하려고하면 값이 상자에 들어갑니다.가치 클래스에 특화된 간단한 사례 클래스를 작성하면이 문제를 피할 수 있습니다. 사례 클래스가 인스턴스화되는 동안 (다른 값 클래스로 값 클래스를 래핑 할 수 없기 때문에) 기본 ProductId
은 런타임에 여전히 String
으로 표시됩니다.
IMO,'underlying'는 그냥'value'보다 나은 방법입니다. –
나는 어떤 표준도 모릅니다. 나는 '내부'를 짧고 분명하게 사용하는 경향이있다. – lmm
저는 이것을하기위한 관용적 인 방법이 없다고 생각합니다. 왜냐하면 value 클래스는 컴파일러에게 좋은 트릭 일 뿐이 기 때문입니다. 그러나 @ om-nom-nom처럼 '근본적인 (underlying)'은 어떤 종류의 래퍼 (wrapper)를 만들어야하는 다른 경우들에서 매우 일반적입니다. – 4lex1v