开放 - 封闭原则问题

时间:2014-12-08 21:21:32

标签: oop open-closed-principle

想象一下一个应用程序,你有一个名为Transaction的类代表一个金融交易。

可以根据Transaction类的属性值和一些业务规则对这些事务进行分类。

名为TransactionType的枚举表示此类分类的可能值:Type1Transaction,Type2Transaction,NotRelevant。

将报告Type1Transactions和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原则违规。

感谢您的帮助。

恩里科

1 个答案:

答案 0 :(得分:0)

使用TypeReporter(或更合适的名称)。它的职责是根据从Transaction:

获得的数据确定交易类型
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);

}

e.g。

class ConcreteTransaction implements Transaction {

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

        return reporter.determineType();
    }

}

因此,Transaction将类型确定委托给另一个对象。这样,如果出现用于确定类型的新类型或新策略,则关闭以进行修改。如果发生这种情况,您可以编写一个新的TypeReporter。

修改: 为了使确定类型的方法更具更改性,您可以保留方便命名的类型,如下所示:

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。