优化Java中复制的代码,避免if子句和强制转换

优化Java中复制的代码,避免if子句和强制转换,java,enums,Java,Enums,我有两门课: DocumentState和ElectronicDocumentState 它们看起来像这样: public class DocumentState extends LabeledEnum { public static final DocumentState CREATED = new DocumentState("created"); // ..... - 15 other statuses } ElectronicDocumentState也扩展了Label

我有两门课:
DocumentState
ElectronicDocumentState

它们看起来像这样:

public class DocumentState extends LabeledEnum {
    public static final DocumentState CREATED = new DocumentState("created");
    // ..... - 15 other statuses
}
ElectronicDocumentState
也扩展了
LabeledEnum
,并且有自己的状态,一些状态是常见的,比如created,另一些是唯一的

然后我在代码中有很多方法将
DocumentState
作为参数,或者返回
DocumentState
。现在,他们还应该使用
ElectronicDocumentState

我还有很多地方可以:

if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
    //do something with document
}
我希望避免“如果”,并避免为
ElectronicDocumentState
创建新方法,因为将来可能会出现更多状态

你会怎么做

因此,使用下面的示例,您将如何重构它,使其能够与
DocumentState
ElectronicDocumentState
一起工作?我有很多这样的方法,现在也可以使用
ElectronicDocumentState
。有人要求我们将电子文档与业务逻辑中的文档混合使用:

private DocumentState getDocumentStateForDetails(Document doc, DocumentState sourceState) {

    if (DocumentState.CREATED.equals(doc.getDocumentState())) {
        if (sourceState.equals(DocumentState.CREATED)) {
            return DocumentState.CREATED;
        } else {
            return DocumentState.BLOCKED;
        }
    } else {
        return sourceState.getDocumentState();
    }
}

如果您担心状态模型的进一步扩展,我建议您考虑使用继承而不是If/switch和instanceof,例如将文档类拆分为Value和state。如果对文档的任何状态都有相同的可用操作集,只需使用经典状态模式,否则,每个状态都可能有自己的可用操作集:

public class Document {

    public static CreatedDocument<Document> create(String author) {
        return new CreatedDocument<>(new Document(author));
    }

    private String author;
    //...

    private Document(String author) {
        //...
    }
}

public class ElectronicDocument extends Document {

    public static CreatedElectronicDocument create(String author, String url) {
        return new CreatedElectronicDocument(author, url);
    }

    private String url;
    //...

    public ElectronicDocument(String author, String url) {
        //...
    }
    //...
}

public interface DocumentState<T extends Document> {

    T getDocument();

    char getCode(); // might be needed for something like logging?
}

public abstract class AbstractDocumentState<T extends Document> implements DocumentState<T> {

    protected final T document;

    protected AbstractDocumentState(T document) {
        this.document = document;
    }

    @Override
    public T getDocument() {
        return document;
    }
}

public class CreatedDocument<T extends Document> extends AbstractDocumentState<T> {

    public CreatedDocument(T document) {
        super(document);
    }

    @Override
    public char getCode() {
        return 'C';
    }

    public DocumentState<T> delete() {
        return new DeletedDocument<>(document);
    }
}

public class CreatedElectronicDocument extends CreatedDocument<ElectronicDocument> {

    public CreatedElectronicDocument(String author, String url) {
        super(new ElectronicDocument(author, url));
    }

    public DownloadElectronicDocument download() {
        return new DownloadElectronicDocument(document);
    }
}

public class DownloadElectronicDocument extends AbstractDocumentState<ElectronicDocument> {

    public DownloadElectronicDocument(ElectronicDocument document) {
        super(document);
        // DO DOWNLOAD HERE
    }

    @Override
    public char getCode() {
        return 'L';
    }

    public DocumentState<ElectronicDocument> delete() {
        return new DeletedDocument<>(document);
    }
}

public class DeletedDocument<T extends Document> extends AbstractDocumentState<T> {

    public DeletedDocument(T document) {
        super(document);
        // DO DELETE HERE
    }

    @Override
    public char getCode() {
        return 'D';
    }
}
这是唯一一种拥有像这样的通用规则的方法

if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
    //do something with document
}

请同时为DocumentState和ElectronicDocumentState工作。

关于您的域,没有足够的信息提供最终答案,但我有一些建议:

  • 似乎DocumentState和ElectronicDocumentState都继承了LabeledEnum;如果你想在你的方法中管理这两个类,你可以让ElectronicDocumentState从DocumentState继承,这样就可以合并这两个类。这将允许在方法中传递ElectronicDocumentState或DocumentState,并可能解决第二个问题
  • 如果要避免,请构建允许方法的列表并对照列表进行检查,如:
  • L

    公共类您的类{
    List allowedStates=//在此处或构造函数中初始化
    ....
    公共方法(…){
    if(allowedStates.contains(doc.getState())){
    //做点什么
    }
    }
    

    allowedStates
    如果是常见情况,可以在单独的类中进行分解。如果您发现重构是可行的,可以检查您是否正在处理并实现它(在一些人的帮助下).

    如果使用正确的枚举,则可以使用
    开关
    。您可以向枚举值添加字段和方法,就像使用常规类一样。这与If“真的”有何不同?但是如果调用的方法是在LabeledEnum中定义的,则可以通过
    LabeledEnum
    调用该方法,而不强制转换到实现类Well,您可以为
    isFoo
    isBar
    等当前通过ifs检查的对象的枚举值添加方法。不知何故,您必须检查某些内容。或者您可以将所有检查放在某种方法中,如
    getStatus()
    ,然后
    int status=getStatus()
    ,并返回结果(最好是一个int)如果(status==1)域建模是一个涉及的主题,有很多要遵循的规则和每个规则的例外,你可以只做
    if(status==1)
    域建模。你在这里问两个独立的问题(一个是如何建模两个独立的枚举,另一个是如何避免在与枚举相关的代码库中出现if)。我建议将此问题分为两个stackoverflow问题,然后给出一个具体且相当完整的示例,这可能是问题的重点。如果还包括何时不使用继承进行建模,则此答案会更有力;它在扩展方面确实有自己的问题。
    if (DocumentSate.CREATED.equals(doc.getState()) || DocumentState.DELETED.equals(doc.getState())) {
        //do something with document
    }
    
    public class YourClass {
    
    List<DocumentSate> allowedStates=//init here or in constructor
    ....
    public void yourMethod(....) {
      if (allowedStates.contains(doc.getState())) {
         //do something
      }
     }