2016-10-19 6 views
-1

DDD 관례에 따라, 나는 작은 AES 암호기/해독기 (wrapping .NET의 AesCryptoServiceProvider)를 구현하는 동안 문제를 겪고있다. DDD - 선택적 상태의 동작 : Service/Value Object?

public class Aes256CbcCryptor : ISymmetricCryptor 
{ 
    private SymmetricAlgorithm AesProvider { get; set; } 

    // Poor man's DI - beside the point 
    public Aes256Cbc() 
    { 
     this.AesProvider = new AesCryptoServiceProvider() 
     { 
      BlockSize = 128, 
      KeySize = 256, 
      Mode = CipherMode.CBC, 
      Padding = PaddingMode.PKCS7, 
      Key = // OH DEAR IT TAKES STATE 
     }; 
    } 
    public Aes256Cbc(SymmetricAlgorithm aesProvider) 
    { 
     this.AesProvider = aesProvider; 
    } 

    public byte[] Encrypt(byte[] keyBytes, byte[] plaintextBytes) 
    {} // TODO 
    public byte[] Decrypt(byte[] keyBytes, byte[] ciphertextBytes) 
    {} // TODO 
} 

당신이 볼 수 있듯이

, .NET의 AesCryptoServiceProvider은 상태입니다 - 그것은 속성으로 키를합니다. 그러나 내가 이해하게되면, 서비스는 stateful하지 않아야합니다.

  1. 키가 주요한 것은 여기서 잘못되고있는 것입니까?
  2. DDD 방식으로 클래스를 구현하는 방법은 무엇입니까?
  3. 경우에 따라 제공된 키로 초기화 된 공급자를 갖는 것이 유용하고 효율적으로 보입니다 (해당 키가 많이 사용되는 경우). stateful 서비스 또는 대안에 대한 정당성이 있습니까?

모든 메소드 호출시 새 제공자를 인스턴스화 할 수 있다고 생각하지만 매우 낭비적인 것 같습니다. 우리는 낭비를 줄이기 위해 캐싱을 구현할 수 있지만 모든 것이 과장된 느낌을 갖기 시작합니다.

또 다른 대안은 내가 대신 Aes256CbcCryptorFactory을 만드는 것입니다. 팩토리의 CreateCryptor(byte[] key)은 실제로 상태 저장 객체 인 값 객체 Aes256CbcCryptor을 반환합니다. 이제 소모적 인 서비스는 다중 cryptor 호출을해야하는 경우이 메소드를 해당 메소드의 범위 내에서 유지할 수 있습니다.

반면에 그러한 소비 서비스는 값 개체를 해당 속성 중 하나에 저장하지 못할 수 있습니다. 그렇게하면 해당 서비스를 상태 저장으로 만들 수 있습니다.

  1. 일부를보고있는 것 중 일부는의 장점입니다. 행동의 유형은 가치 객체에 대해 매우 servicey 인 것처럼 보이지만, 적어도 임시 상태를 가질 수 있습니다.
+0

당신이 댓글을 달았습니다. 귀하의 생성자와 '불쌍한 남자의 DI'. 여기서 DI는 없습니다 : 인스턴스를 생성하기 위해'new' 키워드를 사용하고 있습니다. 아마도 이것은 당신의 문제입니다. 'AesCryptoServiceProvider'를 종속물로 만들어서 컴포지션 루트가 상태에 대해 걱정하지 않아야합니까? –

+0

@DavidOsborne 매개 변수화 된 생성자를 생략했지만 지금 추가했습니다. 매개 변수없는 생성자는 "가난한 사람의 DI"즉, 프레임 워크에 의한 자동 주입의 대안입니다. 나는 당신의 요지에 흥미가 있습니다. 구성 루트가 어떤 키를 사용해야하는지 알 것입니다. 그 루트는 서비스 그 자체일까요, 맞습니까? 그러나 우리는 그것 (그리고 이것)이 stateful이되는 것을 지킬 필요가 없을까요? – Timo

+0

'가난한 사람의 DI'는 컨테이너가없는 DI입니다 (blog.ploeh.dk/2014/06/10/pure-di/). 실제로 합성 루트는 구현에 따라 다릅니다. 선택한 구현에 상태가 필요하다는 사실을 피할 수없는 것처럼 보입니다.당신은 그 상태의 해상도를 더 멀리/더 멀리 밀어 낼 수 있지만 어떤 시점에서는 그 상태를 관리해야 할 것입니다. –

답변

0

나는 이런 식으로 뭔가 함께 갈 것입니다 : 더 해상도를 만들 수있는 용기를 사용

public static sub Main() 
{ 
    var key = SomeConfigSomewhere.GetSetting["key"]; 

    var cryptor = new Aes256CbcCryptor(key); 

    var cipherText = cryptor.Encrypt("[email protected]"); 
} 

:

public class Aes256CbcCryptor : ISymmetricCryptor 
{ 
    private SymmetricAlgorithm AesProvider { get; } 

    public Aes256CbcCryptor(Byte[] key) 
    { 
     // AesCryptoServiceProvider is not a 'volatile' dependency 
     // therefore we don't need to inject it. 
     this.AesProvider = 
      new AesCryptoServiceProvider() 
      { 
       ... 
       Key = key// This is the real dependency, IMHO 
      }; 
    } 
} 

그런 구성 루트 사용 '가난한 사람의 DI는'이 싶습니다 깔끔하지만 기본적으로 동일합니다 :

public static sub Main() 
{ 
    arbitraryContainer 
     .Register 
     .ServiceFor<ISymmetricCryptor>() 
     .Using<Aes256CbcCryptor>() 
     .DependingOn(SomeConfigSomewhere.GetSetting["key"]); 

    var cryptor = arbitraryContainer.Resolve<ISymmetricCryptor>(); 

    var cipherText = cryptor.Encrypt("[email protected]"); 
} 
+0

나는 추상적 인 레이어를 이동하면서 여전히 몇 가지 문제를 안다. 이 Cryptor의 경우 키는 사실상 모든 메서드에서 필요하므로 생성자 종속성으로 이해할 수 있습니다. 이제 이미지에 Cryptor가 종속되어있는 CardNumberCryptor 서비스가 있습니다. 이 서비스는 차례로 RecurringCardPayment 서비스에서 사용되는 다른 서비스에서 사용됩니다. 이제는 RecurringCardPayment의 메소드를 키없이 인스턴스화/테스트 할 수 없습니다. 메소드의 * one *에만 관련 될 수 있습니다. – Timo

+0

'CardNumberCryptor'는'ISymmetricCryptor'에 의존해야합니다. 기본 구현은 그 관심사가 아닙니다. –

+0

Ahh,'CardNumberCryptor'가'ISymmetricCryptor'를 넘겨 주었거나 컨테이너가 이것을합니다. 컨테이너를 사용하면 컨테이너에 어떤 키를 사용해야하는지 알 필요가 있습니다. 이는 컨테이너가 (이 예에서는) Main() 메소드에 매우 강하게 묶여 있음을 의미합니다. 이것은 정상적인 상태입니까? 그렇게 보입니다 ... 정교합니다. – Timo