我有一个应用程序,它必须处理多种类型的文档。
我有一个必须构建报告的服务generateReport(DocumentEntity),将为DocumentEntity的每个类型的子项调用此服务。
问题是我们要构建的报告取决于文档的类型。
我的代码下面有效,但我觉得有更好的方法:
假设我们有DocumentDonationEntity&扩展DocumentEntity的DocumentBookEntity:
public abstract class DocumentEntity {
protected Long id;
protected String name;
// getters & setters
}
public class DocumentDonationEntity extends DocumentEntity {
private String donatorName;
// getters & setters
}
public class DocumentBookEntity extends DocumentEntity {
private Long price;
// getters & setters
}
和ReportDataBook&和ReportDataDonation扩展了ReportData:
public abstract class ReportData {
protected Long id;
protected String name;
public void checkNotNull() throws MyException {
if this.id == null
throw new myException();
if this.name == null
throw new myException();
// other generic stuff
}
// getters & setters
}
public class ReportDataBook extends ReportData {
private String price;
public void checkNotNull() throws MyException {
super.checkNotNull();
if this.price == null
throw new myException();
// other stuff specific to books
}
// getters & setters
}
public class ReportDataDonation extends ReportData {
private String donatorName;
public void checkNotNull() throws MyException {
super.checkNotNull();
if this.donatorName == null
throw new MyException();
// other stuff specific to donations
}
// getters & setters
}
加上一个utils类:
public class Utils {
public ReportData fillReport(DocumentEntity document) throws Exception {
if (document instanceof DocumentBookEntity) {
ReportDataBook data = new ReportDataBook();
completeReportData(data, (DocumentBookEntity) document);
completeReportData(data, document);
return data;
} else if (document instanceof DocumentDonationEntity) {
ReportDataDonation data = new ReportDataDonation ();
completeReportData(data, (DocumentDonationEntity) document);
completeReportData(data, document);
return data;
}
return null;
}
public void completeReportData(ReportData data, DocumentEntity document) {
// some generic stuff
}
public void completeReportData(ReportDataBook data, DocumentBookEntity document) {
// some stuff specific to books
}
public void completeReportData(ReportDataDonation data, DocumentDonationEntity document) {
// some stuff specific to donations
}
}
然后我有一个服务:
@Service
public class MyService implements IMyService {
@Override
public boolean generateReport(DocumentEntity document) throws MyException {
ReportData data = initializeReport(document);
// do some other stuff
}
private ReportData initializeReport(DocumentEntity document) throws myException {
if (document instanceof DocumentBookEntity) {
ReportDataBook data = (ReportDataBook) utils.fillReport(document);
data.checkNotNull();
return data;
} else if (document instanceof DocumentDonationEntity) {
ReportDataDonation data = (ReportDataBook) utils.fillReport(document);
data.checkNotNull();
return data;
}
return null;
}
}
答案 0 :(得分:0)
每当您找到instanceof
时,您可以考虑根据http://refactoring.com/catalog/replaceConditionalWithPolymorphism.html重构多态性
我做了一些UML图表,因为我觉得用子类层次结构来设置一个设计更容易:
我会考虑Factory Method模式:
我将DocumentEntity
层次结构视为此模式中的Creator
,将ReportData
视为Product
:
上面的示例仅显示了一个工厂方法实现。另一个(DocumentBookEntity
)将返回new ReportBookDonation()
。
然后ReportData
类处理DocumentEntity
子类型的所有细节。我不认为你真的需要MyService
的东西了。 MyService.initializeReport()
应移至ReportData
层次结构中;它现在在子类中是多态的(消除了instanceof
条件)。它与Utils.fillReport()
的代码相同 - 它是特定版本报告提供的服务。
如果其他Utils
方法不依赖于子类型,则将它们放在ReportData
抽象类中。就个人而言,我称之为Report
类,因为对象更多地是关于行为(服务)而不是数据结构。
因此,要生成报告,它将如下所示:
DocumentEntity doc; // it's really an instance of a subclass
...
ReportData reporter = doc.createReportService(); // factory method call (polymorphic)
...
reporter.initializeReport(); // lazy initialization
您可以将initialize
和fill
内容放在子类的构造函数中,一旦调用工厂方法,就会生成报告。