Принцип единой ответственности и дизайн службы/репозитория

Мне интересно, как лучше всего разделить ответственность в следующем примере.

Существует объект Foo, который имеет несколько полей id и несколько полей reallySecretImportantData. Id — это простой идентификатор для ссылки на объект, а reallySecretImportantData — это данные, которые должны быть зашифрованы в базе данных, так как база данных — единственное уязвимое место в данном примере.

Теперь, если у нас есть FooService с методами void storeFoo(Foo foo) и Foo readFoo(Id id).

У нас также есть FooRepository со стандартными методами CRUD, которые хранят объекты Foo в базе данных.

Теперь, поскольку я хочу сохранить reallySecretImportantData в зашифрованном виде, мне нужно где-то зашифровать и где-то расшифровать.

Поскольку в обязанности FooRepositorys не должны входить криптооперации, логичным местом будет FooService.

Теперь, если бы я был в какой-то среде разработки, я бы хотел, чтобы для целей разработки и тестирования сохранить reallySecretImportantData в виде простого текста.

При условии, что я использую какой-то DI, я мог бы написать 2 реализации моей службы, одну для prod и другую для dev/test, и просто настроить DI для использования prod в производственной среде и dev/test в среде dev&test.

Теперь, если в ближайшем будущем возникнет запрос на изменение способа хранения reallySecretImportantData, я мог бы просто написать другую реализацию сервиса и использовать свой DI-фреймворк для его внедрения.

Будет ли этот простой дизайн достаточно хорош для текущего макета?


person ioreskovic    schedule 15.12.2015    source источник


Ответы (2)


Ваш дизайн напоминает мне паттерн стратегии. FooService можно рассматривать как интерфейс стратегии.

Но я предпочитаю добавлять в этот интерфейс методы encrypt() и decrypt() вместо store() и read(). Мы можем назвать его как FooCryptoStrategy.

Кроме того, FooRepository может быть создан с помощью объекта FooCryptoStrategy. Таким образом, вы можете CRUD Foo объекты не касаться проблем с шифрованием. Вы можете создать несколько реализаций FooCryptoStrategy для выпуска и тестирования. Даже вы можете реализовать NonCryptoStrategy.

В заключение, используя шаблон стратегии, мы можем назначить одну ответственность одному классу:
Foo: хранение данных
FooCryptoStrategy: шифрование и дешифрование Foo объектов
FooRepository: создание постоянных объектов Foo.
Класс контроллера: создание конкретных объектов FooCryptoStrategy и FooRepository.

person Q Q    schedule 15.12.2015

Зачем вам "сервис"?

Рассмотрим объект Secret, который знает, как шифровать/расшифровывать/шифровать, и объект управления данными, который имеет дело с сохраняемостью.

Сделайте свою функциональность «подключаемой», реализовав свои алгоритмы шифрования с общим интерфейсом, например. IEncrypt. Так, например, у вас может быть как AesEncryptor, так и TestPlainEncryptor.

// simple non-dependency-injection example    
Secret encrypted = new Secret(new AesEncryptor, "key", "my secret stuff");
new SecretDM().Save(s);

Secret retrieved = new SecretDM().Get("key");
// println(retrieved.Decrypt());
person aryeh    schedule 15.12.2015
comment
Ну, проблема в том, что я не могу изменить схему базы данных. Другая проблема заключается в том, что, учитывая ваше решение, я должен каким-то образом сохранить экземпляр интерфейса IEncrypt, чего я бы не хотел, и я не уверен, что это хорошее решение. - person ioreskovic; 15.12.2015