Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/oop/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 通过设计模式重构交换机外壳的遗留实例_Java_Oop_Wrapper_Instanceof_Visitor Pattern - Fatal编程技术网

Java 通过设计模式重构交换机外壳的遗留实例

Java 通过设计模式重构交换机外壳的遗留实例,java,oop,wrapper,instanceof,visitor-pattern,Java,Oop,Wrapper,Instanceof,Visitor Pattern,我公司的旧代码普遍使用交换机外壳的instanceof,其形式如下: if(object instanceof TypeA) { TypeA typeA = (TypeA) object; ... ... } else if(object instanceof TypeB) { TypeB typeB = (TypeB) object; ... ... } ... ... 更糟糕的是,问题中的几个TypeX类实际上是第三方库中的类的包装 建议在第三方类上使用

我公司的旧代码普遍使用交换机外壳的instanceof,其形式如下:

if(object instanceof TypeA) {
   TypeA typeA = (TypeA) object;
   ...
   ...
}
else if(object instanceof TypeB) {
   TypeB typeB = (TypeB) object;
   ...
   ...
}
...
...
更糟糕的是,问题中的几个TypeX类实际上是第三方库中的类的包装

建议在第三方类上使用访问者设计模式和专用访问者设计模式包装器,这是一个不错的方法

然而,在提出这种方法的代码审查会议期间,instaceof交换机外壳每次重构所需的样板代码额外开销问题导致该机制被拒绝

我想解决这个持续存在的问题,我正在考虑一种解决问题的通用方法:

一个实用程序类,它将使用对访问对象的泛型引用包装访问者设计模式。其思想是一次性实现visitor实用程序类的通用核心,并在需要时为TypeX对象行为提供特定的实现——希望甚至通过功能实现类的OO扩展重用一些实现

我的问题是——这里有人做过类似的事情吗?如果没有-你能指出任何可能相关的优点/缺点吗

编辑: 太多样板代码=专门为instanceof switch case的每个实例实现访问者设计模式。如果visitor DP不是使用泛型实现的,那么这显然是冗余的,并且会导致大量代码重复

至于我心目中的通用访问者DP实用程序:

首先,对访问者DP使用反射,如图所示

其次,泛型的以下用法(基于反射访问者):

至于访客设计如何处理这个问题

public interface Visitor
{
   // notice how I just binded my interface to a specific set of methods?
   // this interface will have to be generic in order to avoid an influx of
   // of dedicated interfaces
   public void visit(TypeA typeA);
   public void visit(TypeB typeB);
}
public interface Visitable
{
   public void accept(Visitor visitor);
}

public class BoilerPlateExampleVisitable<T> implements Visitable
{
   // This is basically a wrapper on the Types
   private T typeX;
   public BoilerPlateExampleVisitable (T typeX) {
      this.typeX = typeX;
   }
   public void accept(Visitor visitor) {
      visitor.visit(typeX);
   }
}

public class BoilerPlateExampleVisitor implements Visitor
{
   public void visit(TypeA typeA) {
      typeA.specificMethodTypeA(...)......;
   }
   public void visit(TypeB typeB) {
      typeB.completeyDifferentTypeBMethod(...)......;
   }
}

public static final BoilerPlateExampleVisitor BOILER_PLATE_EXAMPLE_VISITOR = new BoilerPlateExampleVisitor();
public static void main(....) {
    TypeA object = .....; // created by factory
    BoilerPlateExampleVisitable boilerPlateVisitable = VisitableFactory.create(object); // created by dedicated factory, warning due to implicit generics
    boilerPlateVisitable.accept(BOILER_PLATE_EXAMPLE_VISITOR);
}
公共界面访问者
{
//注意我是如何将接口绑定到一组特定的方法的吗?
//该接口必须是通用的,以避免数据流入
//专用接口的设计
公众无效访问(A型);
公众无效访问(B类);
}
公共界面可访问
{
公众无效接受(访客);
}
公共类样板ExampleVisiTable实现Visitable
{
//这基本上是类型的包装器
私人T型;
公共样板示例可访问(T typeX){
this.typeX=typeX;
}
公众无效接受(访客){
访客访问(typeX);
}
}
公共类样板示例Visitor实现Visitor
{
公众无效访问(TypeA TypeA){
类型A.特定方法类型A(…)。。。。。。;
}
公众无效访问(类型B类型B){
类型B.完全不同类型B方法(…)。。。。。。;
}
}
公共静态最终样板ExampleVisitor锅炉\uPlate\uExample\uVisitor=新样板ExampleVisitor();
公共静态空干管(……){
TypeA对象=……;//由工厂创建
BoilerPlateExampleVisitable boilerPlateVisitable=VisitableFactory.create(object);//由专用工厂创建,由于隐式泛型而发出警告
样板可访问。接受(锅炉样板示例访客);
}
看起来像。这样的代码可能来自一组异源的业务对象类,如Excel ReportX、Zip、TableY,以及诸如打开、关闭、保存等操作

实际上,这种编程会导致类之间的巨大耦合,并且存在所有情况的完整性和可扩展性问题

在多态性的情况下,某些业务对象的实际包装器应该提供操作(打开、保存、关闭)

此机制类似于JavaSwing,其中编辑字段有其操作列表(剪切、复制、粘贴等),树视图有一组重叠的操作。根据焦点,实际操作将安装在“操作”菜单中

声明性的规范可能是有序的:比如说一个“保存”bean及其操作的XML

如果你在雷达上有一些强的MVC <强>范式,请考虑如下: 每个动作都可以有参数。使用PMVC(我的想法),一个与模型类不同的参数类,因为这些信息具有不同的生命周期,并且是常量

这里的道路可以是:

  • 具有两个业务对象和两个操作的原型
  • 使用一个包含所有(旧代码)的变形业务对象进行重构
  • 慢慢地将一个又一个类移动到它们自己的业务对象
  • 第一次从用于清理新体系结构的polymorph业务对象中删除
我会避免使用继承(带有open/save的BaseDocument),因为这可能不适合更异构的现实,并且可能会导致并行类层次结构(带有XContainer和XObject的XDoc)

如何真正做到这一点仍然是你的工作。我还渴望了解是否存在一个既定的范例


询问伪代码 我们需要做一些原型的分析——一个概念的证明。但是,发现了(动态)功能/特性

public interface Capabilities {
    <T> Optional<T> as(Class<T> type);
}
基础设施将是:首先,功能和发现的注册可以放在一个单独的类中

/**
 * Capabilities registration & discovery map, one can delegate to.
 */
public class CapabilityLookup implements Capabilities {

    private final Map<Class<?>, Object> capabilitiesMap = new HashMap<>();

    public final <T> void register(Class<T> type, T instance) {
        capabilitiesMap.put(type, instance);
    }

    @Override
    public <T> Optional<T> as(Class<T> type) {
        Object instance = capabilitiesMap.get(type);
        return instance == null ? Optional.empty()
                                : Optional.of(type.cast(instance));
    }
}
/**
*功能注册和发现映射,可以委派给。
*/
公共类功能Lookup实现了这些功能{
private final Map似乎是这样的。这样的代码可能来自一组异源的业务对象类,如Excel ReportX、Zip、TableY,以及像Open、Close、Save等操作

实际上,这种编程会导致类之间的巨大耦合,并且存在所有情况的完整性和可扩展性问题

在多态性的情况下,某些业务对象的实际包装器应该提供操作(打开、保存、关闭)

这种机制类似于JavaSwing,其中一个编辑字段具有i
public interface Capabilities {
    <T> Optional<T> as(Class<T> type);
}
void f(Capabilities animal) {
    int distance = 45;
    animal.as(Flying.class).ifPresent(bird -> bird.fly(distance));
}
/**
 * Capabilities registration & discovery map, one can delegate to.
 */
public class CapabilityLookup implements Capabilities {

    private final Map<Class<?>, Object> capabilitiesMap = new HashMap<>();

    public final <T> void register(Class<T> type, T instance) {
        capabilitiesMap.put(type, instance);
    }

    @Override
    public <T> Optional<T> as(Class<T> type) {
        Object instance = capabilitiesMap.get(type);
        return instance == null ? Optional.empty()
                                : Optional.of(type.cast(instance));
    }
}
/** Extended legacy class. */
public class Ape implements Capabilities {

    private final CapabilityLookup lookup = new CapabilityLookup();

    public Ape() {
        lookup.register(String.class, "oook");
    }

    @Override
    public <T> Optional<T> as(Class<T> type) {
        return lookup.as(type); // Delegate to the lookup map.
    }
}

/** Extended legacy class. */
public class Bird implements Capabilities {

    private final CapabilityLookup lookup = new CapabilityLookup();

    public Bird() {
        lookup.register(Flying.class, new Flying() {
            ...
        });
        lookup.register(Singing.class, new Singing() {
            ...
        });
    }

    @Override
    public <T> Optional<T> as(Class<T> type) {
        return lookup.as(type); // Delegate to the lookup map.
    }
}
public class NewOperationVisitor implements Visitor
{
   public void visit(TypeA typeA) {
        // apply my new operation to typeA
   }
   public void visit(TypeB typeB) {
        // apply my new operation to typeB
   }
   ...
}
public class TypeX implements Operator 
{
    public void operation1() {
        // pretty simple
    }

    public void operation2() {
        // pretty simple
    }
}
public void someMethod() {
    ...
    ...
    if(object instanceof TypeA) {
       TypeA typeA = (TypeA) object;
       ...
       ...
    }
    else if(object instanceof TypeB) {
       TypeB typeB = (TypeB) object;
       ...
       ...
    }
    ...
    ...
}
public void someMethod() {
    ...
    ...
    this.whatYouDoInTheSwitch(object, some args);
    ...
    ...
}
private void whatYouDoInTheSwitch(Object object, some args) {
    if(object instanceof TypeA) {
       TypeA typeA = (TypeA) object;
       ...
       ...
    }
    else if(object instanceof TypeB) {
       TypeB typeB = (TypeB) object;
       ...
       ...
    }
}
/** Needs fix: use Visitor Pattern, because... (growing set of operations, ...) */
private void whatYouDoInTheSwitch(Object object, some args) {
    ...
}
this.whatYouDoInTheSwitch(object, other args);
object.whatYouDoInTheSwitch(this, other args);
private void whatYouDoInTheSwitch(Object object, some args) {
    if(object instanceof TypeA) {
        this.doIt((TypeA) object, some args);
    }
    else if(object instanceof TypeB) {
        this.doIt((TypeB) object, some args);
    }
}
doIt(Caller caller, args);
private void whatYouDoInTheSwitch(Object object, some args) {
    if(object instanceof TypeA) {
        ((TypeA) object).doIt(this, some args);
    }
    else if(object instanceof TypeB) {
        ((TypeB) object).doIt(this, some args);
    }
}
private void whatYouDoInTheSwitch(Object object, some args) {
    if(object instanceof TypeA) {
        object.doIt(this, some args);
    }
    else if(object instanceof TypeB) {
        object.doIt(this, some args);
    }
}
private void whatYouDoInTheSwitch(Object object, some args) {
    object.doIt(this, some args);
}
public void someMethod() {
    ...
    ...
    object.doIt(this, some args);
    ...
    ...
}