我正在研究我们Web应用程序的报告模块。有六个报告可供客户端使用,每个报告都有一个代码。问题是,现在该模块没有关闭以进行修改,以可能添加新报告,从而违反了OCP。
为了阐明,我有以下一组类:
所有其他报表继承的通用报表类:
public abstract class Report
{
private final String code;
Report(String code)
{
this.code = code;
}
public String getCode() { return code; }
public abstract byte[] generate();
}
一个 Servlet,用于管理用于生成报告的 POST 请求:
public class ReportServlet extends HttpServlet
{
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException
{
Report requested = ReportRegistry.lookup(req.getParameter("report_code"));
byte[] bytes = requested.generate();
// attach bytes to response
}
}
报表注册表,用于存储所有现有报表以供以后访问:
public class ReportRegistry
{
private static final Map<String, Report> registry = new HashMap<>();
static
{
// Violates OCP!
registerReport( GlobalReport.getInstance() );
registerReport( AvailablePackagesReport.getInstance() );
registerReport( BadgeReport.getInstance() );
registerReport( PlacementReport.getInstance() );
registerReport( TerminalReport.getInstance() );
registerReport( VerActReport.getInstance() );
}
private ReportRegistry() { }
static void registerReport(final Report report)
{
registry.put(report.getCode(), report);
}
public static Report lookup(final String reportCode)
{
return registry.get(reportCode);
}
}
但是,ReportRegistry
违反了 OCP,因为每次创建新报表时,我们都需要向其静态块添加一个条目。
我的问题是:如何在没有任何明确提及的情况下自动注册Report
的任何新子类?
OCP更适合Report
本身,并且ReportRegistry
位于类层次结构之外将是一个有效的设计。
也就是说,如果要避免每次创建Report
子类时都修改ReportRegistry
,则可以使用一些反射技巧来查找所有此类子类,或者创建一个注释,ReportRegistry
可以搜索该注释以将所有类注册到实例。
看看 https://github.com/ronmamo/reflections。我从未尝试过这个库,但它看起来可以满足您的需求(检索已知类的所有子类(。
然后,您可以在ReportRegistry
静态块中注册它们。