Java 设计:解决这个问题的最佳方法?
到目前为止,我已经多次遇到这个设计问题,我总是用下面的方法来解决它。然而,我只是想知道这是正确的方法还是有更好的方法。语言是Java,但我猜这个问题也会出现在其他强类型系统中 问题是这样的:Java 设计:解决这个问题的最佳方法?,java,oop,Java,Oop,到目前为止,我已经多次遇到这个设计问题,我总是用下面的方法来解决它。然而,我只是想知道这是正确的方法还是有更好的方法。语言是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 {
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);
interface P
{
void handle();
}
class P1 implements P {
int p3; int p4;
void handle () {...}
}
class P2 implements P {
int p5; int p6;
void handle () {...}
}
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.
}
}
现在,这个代码从来没有让我完全满意
第一,我不喜欢混凝土浇筑的芬德尔。具体的幻影者知道他们要在编译时处理的类型。为什么要等到运行时?(这是Java语言的一个限制,任何技术都可以避免,比如双重分派?我无法理解)
工厂紫罗兰的开闭式原则。我通常通过反射/属性文件来实现它,以避免OCP。编辑:随着我们继续添加更多的P实例,我们需要不断更改工厂(除非使用反射)
我还对具体的p实现使用了注释。再次强调,它会破坏OCP,更糟糕的是,OCP可以有不同类型的处理程序,具有不同的目的
我很想知道专家们对此的看法。同样,这段代码主要在Spring容器中运行,因此任何其他AOP解决方案都会引起我的兴趣。正如@bmorris591所说,“泛型是整理它的方法”。但这可能只是因为你的例子很简单,可以这样做
这真的取决于上下文。你编写代码的方式让我想起了。这是一种双重分派的方法。它有一些优点和缺点。最大的缺点是它会使代码复杂化
在某些情况下,您将p设为PHandler所希望的逻辑接口:
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);
interface P
{
void handle();
}
class P1 implements P {
int p3; int p4;
void handle () {...}
}
class P2 implements P {
int p5; int p6;
void handle () {...}
}
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.
}
}
同样,这也有利弊。从OO的角度来看,将句柄实现放在P实现中可能没有意义。这都是关于上下文的。如果您知道
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);
}
因此,您有一个访问者逻辑的集合
,然后使用PVisitor
访问p
实例,多态性将计算出是什么
编辑
在OP的评论之后,我有了一个想法
抽象工厂模式与访问者模式和一些泛型相结合怎么样
我们的想法是,我们知道,如果我们添加一种新类型的处理程序
,那么就需要改变一些东西——从逻辑上讲,应该是HandlerFactory
实现,而不是p
s。如果我们有一个抽象HandlerFactory
,每个P
实现负责返回一个处理它的实例,该怎么办
然后,工厂有许多方法返回特定的处理程序,即getDatabaseHandler
等。这些Handler
s可以从泛型Handler
类继承
这个想法是这样的:
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);
interface P
{
void handle();
}
class P1 implements P {
int p3; int p4;
void handle () {...}
}
class P2 implements P {
int p5; int p6;
void handle () {...}
}
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.
}
}
因此,您可以从该实例获取实例的特定数据库处理程序。泛型是整理该实例的方法。不确定泛型有何帮助,因为我们的问题是运行时调度,而泛型在运行时不存在。有什么例子吗?
PHandler。。。无效句柄(T)
然后P1Handler。。。无效句柄(P1)
类似的东西。我面前没有编译器,因此可能无法编译,但概念就在那里。谢谢,我明白了。它确实解决了强制转换问题。P主要是数据类,并且总是会有不同类型的处理程序。例如,DBHandler负责将P保存在db中。根据P的类型,它可以是OracleDbHandler或SQLDbHandler。PublishHandler将再次基于类型发布P。我们将使用HTMLPublishHandler或JMSPublishHandler。因此,将所有处理程序逻辑缠绕在具体的P实现中在这种上下文中是不起作用的。这听起来似乎符合访问者模式的工作方式。同样,你也可以用泛型来实现。如果你不能从访客模式中获得任何优势,我更喜欢后者。你是对的。当所有已知的混凝土P已知时,访客可申请避免浇筑。但问题是,当我们想要添加新的OCP实现时,PVisitor又会对OCP产生影响。在这种情况下,我宁愿让工厂成为紫罗兰OCP而不是访客。因为你可以写智能工厂来寻找幻影,避免OCP。谢谢分享这个想法。然而,我想知道你会选择哪种解决方案?我个人认为查找实现的简单工厂模式,在这种情况下,对于不同类型的处理程序,我们将有不同的handlerFactory。AbstractFactory为不同类型的处理程序引入了更多的耦合。这两种图案仍然是紫罗兰色的OCP。我不知道你们计划有多少种不同的处理者,所以我真的不能说。基本问题是,如果不想强制转换,那么需要在编译时了解类型——根据定义,需要进行耦合。依赖项注入框架可以在某种程度上解决这个问题,但是由于擦除的原因,您不能使用泛型,应该在何处注入什么也不完全清楚。