2014-12-08 2 views
0

Представьте приложение, в котором у вас есть класс с именем «Транзакция», представляющая собой финансовую операцию.Открытый вопрос с открытым кодом

Эти операции могут быть классифицированы на основе значений свойств класса Transaction и некоторых бизнес-правил.

Перечислимое имя TransactionType представляет возможное значение такой классификации: Type1Transaction, Type2Transaction, NotRelevant.

Тип1Transactions и Type2Transactions будут сообщены, поскольку они несколько подозрительны, NotRelevant транзакций не сообщается.

Этот вид классификации интересен только для того, чтобы сообщать о транзакции и не представляет собой внутреннее свойство класса Transaction (поэтому класс Transaction не имеет свойства, представляющего эту классификацию).

Ну, на данный момент мы хотим написать класс, ответственность которого определяется классификацией данной транзакции, назовем ее TransactionClassificator.

Его интерфейс выставляет метод GetTransactionType(), возвращаемым значением которого является TransactionType. Наиболее очевидная реализация выглядит следующим образом:

public TransactionType GetTransactionType() 
{ 
    if(IsType1Transaction()) 
     return TransactionType.Type1Transaction; 

    if(IsType2Transaction()) 
     return TransactionType.Type2Transaction; 

    return TransactionType.NotRelevant; 
} 

Этот метод явно нарушает OCP принципа: он не закрыт для изменений, потому что она должна быть изменена каждый раз, когда будет введена новая величина для перечисления TransactionType. Я не могу понять, как использовать абстракцию для исправления нарушения принципа OCP в этом конкретном сценарии.

Спасибо за помощь.

Энрико

+0

Я не вижу проблемы.Здесь выполняется абстракция, конечно, ее нужно модифицировать, если изменяется характер абстракции. – Barmar

ответ

0

Используйте TypeReporter (или более подходящее название). Это ответственность будет определять тип транзакции, основываясь на данных, которые она получает от сделки:

interface TypeReporter { 

    /** 
    * Methods required for transaction to feed the data required for the 
    * business rules to determine the transacion type 
    */ 

    public TransactionType determineType(); 
} 

Теперь сделка может сообщать свой собственный тип с помощью TypeReporter в:

interface Transaction { 

    /** among other things **/ 

    public TransactionType reportType(TypeReporter reporter); 

} 

например

class ConcreteTransaction implements Transaction { 

    public TransactionType reportType(TypeReporter reporter) { 
     reporter.hereIsThis(someProperty); 
     reporter.andThat(someOtherProperty); 

     return reporter.determineType(); 
    } 

} 

Таким образом Transaction делегирует определение типа другому объекту. Таким образом, он закрывается для модификации, если возникает новый тип или новая стратегия определения типа. Если это произойдет, вы напишите новый TypeReporter.

Edit: Для того, чтобы метод для определения типа более изменить резистентный вы можете держать удобно названные типы, как так:

public enum TransactionType { 
    Type1Transaction, 
    Type2Transaction, 
    NotRelevant 
} 

где метод, который возвращает тип может быть:

public TransactionType determineType() { 
    //business logic to determine the type goes here 
    //represent that type as a string (String determinedType) 

    //now we check if that string is a valid enum value, if not returning NotRelevant 
    try { 
     return Choices.valueOf(determinedType + "Transaction"); 
    } catch (IllegalArgumentException ex) { 
     return TransactionType.NotRelevant; 
    } 
} 

Таким образом, если TransactionType становится релевантным, вы можете просто добавить его как новое значение TransactionType и больше не будет возвращать NotRelevant.

+0

спасибо, что ответили. Просто для лучшего понимания, сколько конкретной реализации интерфейса TypeReporter мне нужно написать в примере, который я показал в моем вопросе? –

+0

Хм, вы можете это сделать. С другой стороны, теперь мое решение, похоже, решает проблему, которую вы не хотели решать. Шаблон стратегии здесь изолирует объект Transaction от изменения, если алгоритм для определения Типа должен измениться; но теперь я понимаю, что это не то, что вы искали. Теперь я думаю, что транзакция по-прежнему хорошо подходит для определения собственного типа, либо с помощью вспомогательного объекта, либо без него (TypeReporter), поскольку он сохраняет транзакцию в инкапсулированном виде. Что касается фиксации постоянных модификаций if/else, вы можете попытаться быть умными, назвав ваши значения Enum удобными. (редактировать) – Weltschmerz

Смежные вопросы