优化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工作。关于您的域,没有足够的信息提供最终答案,但我有一些建议:
公共类您的类{
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
}
}