到目前为止,我已多次解决这个设计问题,并且我总是通过以下方式解决它。但是,我只是想知道这是否是正确的方法,或者是否有更好的方法。该语言是Java,但我猜这个问题也会出现在其他强类型系统中。
问题是这样的:
abstract class P
{
int p1; int p2;
}
class P1 extends P {
int p3; int p4;
}
class P2 extends P {
int p5; int p6;
}
abstract class PHandler {
void handle(P p)
}
class P1Handler{
void handle(P p) {
P1 castedP = (P1) p;
//.....handle logic with P1
}
}
class P2Handler{
void handle(P p) {
P2 castedP = (P2) p;
//.....handle logic with P2
}
}
final class PHandlerFactory {
PHandler getPhandler(P p) {
//test on P , if/else on either InstanceOf or some attribute of P
return concrete P
}
}
// client code
P p = getPFromSomewhereAtRuntime();
PHandler pHandler = factory.get(p);
pHandler.handle(p);
现在,这段代码从未让我满意。
第一,我不喜欢混凝土PHandler的铸造。具体的PHandler知道他们想要在编译时处理它们的类型。为什么要等到运行时? (它是一种Java语言限制,可以通过双重调度等任何技术来避免?无法理解它) 第二,工厂违反了开放原则 - 原则。我通常通过reflection / properties文件来实现它以避免OCP。编辑:当我们继续添加更多P的实例时,我们需要不断更改工厂(除非使用反射)我还在Concrete P实现上使用了Annotations。同样,它违反OCP,更糟糕的是,P可以有不同类型的处理程序,具有不同的目的。
我真的很想知道专家对此的看法。同样,这段代码主要在Spring容器中运行,因此任何其他AOP解决方案也会让我感兴趣。
答案 0 :(得分:2)
正如@ bmorris591所说,“仿制药是整理它的方法”。但这可能只是因为你的例子很简单,就这样做了。
这实际上取决于背景。编写代码的方式让我想起了the visitor pattern。这是双重调度的一种方式。它有一些优点和缺点。最大的问题是它会使代码复杂化。
在某些情况下,你使P成为PHandler所具有的逻辑接口:
interface P
{
void handle();
}
class P1 implements P {
int p3; int p4;
void handle () {...}
}
class P2 implements P {
int p5; int p6;
void handle () {...}
}
同样,这有利有弊。从OO的角度来看,将句柄实现放在P实现中是没有意义的。这完全取决于背景。
答案 1 :(得分:1)
如果你知道P
的具体实现,即如果它们不是从某个地方提供的,那么你可以使用访问者模式:
abstract class P {
int p1;
int p2;
abstract void visit(final PVisitor visitor);
}
class P1 extends P {
int p3;
int p4;
@Override
void visit(PVisitor visitor) {
visitor.doStuff(this);
}
}
class P2 extends P {
int p5;
int p6;
@Override
void visit(PVisitor visitor) {
visitor.doStuff(this);
}
}
interface PVisitor {
void doStuff(P1 p);
void doStuff(P2 p);
}
因此,您拥有Collection<PVisitor>
访问者逻辑,然后使用P
访问您的PVisitor
实例,并且多态将找出您的内容。
修改强>
根据OP的评论我有一个想法。
抽象工厂模式与访客模式和一些泛型相结合。
我们知道,如果我们添加新类型Handler
,那么需要更改某些内容 - 逻辑上它应该是HandlerFactory
实现而不是P
。如果我们有abstract HandlerFactory
并且每个P
实现负责返回处理它的实例,该怎么办。
然后工厂有许多返回特定处理程序的方法,即getDatabaseHandler
等。这些Handler
可以从泛型Handler
类继承。
这个想法看起来像这样:
abstract class P {
int p1;
int p2;
public abstract HandlerFactory<? extends P> getHandlerFactory();
}
class P1 extends P {
int p3;
int p4;
@Override
public HandlerFactory<P1> getHandlerFactory() {
return new P1HandlerFactory(this);
}
}
class P2 extends P {
int p5;
int p6;
@Override
public HandlerFactory<? extends P> getHandlerFactory() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
abstract class HandlerFactory<T extends P> {
private T t;
public HandlerFactory(T t) {
this.t = t;
}
public T getT() {
return t;
}
public abstract DatabaseHandler<T> getDatabaseHandler();
public abstract JMSHandler<T> getJMSHandler();
}
abstract class Handler<T extends P> {
private final T t;
public Handler(T t) {
this.t = t;
}
public T getT() {
return t;
}
}
abstract class DatabaseHandler<T extends P> extends Handler<T> {
public DatabaseHandler(T t) {
super(t);
}
public abstract void persist(Connection con);
}
abstract class JMSHandler<T extends P> extends Handler<T> {
public JMSHandler(T t) {
super(t);
}
public abstract void send();
}
class P1HandlerFactory extends HandlerFactory<P1> {
public P1HandlerFactory(P1 t) {
super(t);
}
@Override
public DatabaseHandler<P1> getDatabaseHandler() {
return new P1DatabaseHandler(getT());
}
@Override
public JMSHandler<P1> getJMSHandler() {
return new P1JMSHandler(getT());
}
}
class P1DatabaseHandler extends DatabaseHandler<P1> {
public P1DatabaseHandler(P1 p1) {
super(p1);
}
@Override
public void persist(Connection con) {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
class P1JMSHandler extends JMSHandler<P1> {
public P1JMSHandler(P1 p1) {
super(p1);
}
@Override
public void send() {
throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
}
}
因此,P
的每个实施都附带了HandlerFactory
个伴随,添加P
的新实现只需要为其实施HandlerFactory
。例如,使用泛型允许从P1A
继承的P1B
和P1
仅使用P1Handler
,如果它们不需要任何更改。
如果添加了新类型的Handler
,则需要更改所有HandlerFactory
实现,以获得获取Handler
类型的方法,但P
s不需要改变。
用法看起来像
final P1 p1 = new P1();
final DatabaseHandler<P1> databaseHandler = p1.getHandlerFactory().getDatabaseHandler();
因此,您可以从该实例获取实例的特定数据库处理程序。