首页 > 解决方案 > 序列化复合的最佳方式 - (设计模式)

问题描述

我有以下实现复合设计模式的java代码:

//composite designed for type safety (all Leaf-only operations only in leaf)
interface Component extends Visitable {
  void enable();
  void disable();
}

class CompositeA implements Component {
  private String compositeData;
  private boolean enabled;
  private Set<Component> components = new HashSet<>();

  CompositeA(String compositeData) {
    this.compositeData = compositeData;
  }

  void addChild(Component component){
    this.components.add(component);
  }

  String getCompositeData() {
    return compositeData;
  }

  Set<Component> getComponents() {
    return components;
  }

  @Override
  public void enable() {
    this.enabled = true;
  }

  @Override
  public void disable() {
    this.enabled = false;
  }

  @Override
  public Object accept(ComponentVisitor visitor) {
    return visitor.visit(this);
  }
}

class CompositeB implements Component{
  private int compositeData;
  private boolean enabled;
  private Set<Component> components = new HashSet<>();

  CompositeB(int compositeData) {
    this.compositeData = compositeData;
  }

  void addChild(Component component){
    this.components.add(component);
  }

  int getCompositeData() {
    return compositeData;
  }

  Set<Component> getComponents() {
    return components;
  }

  @Override
  public void enable() {
    this.enabled = true;
  }

  @Override
  public void disable() {
    this.enabled = false;
  }

  @Override
  public Object accept(ComponentVisitor visitor) {
    return visitor.visit(this);
  }
}

class Leaf implements Component {
  private boolean enabled;
  private String[] leafData;

  Leaf(String[] leafData) {
    this.leafData = leafData;
  }

  String[] getLeafData() {
    return leafData;
  }

  @Override
  public void enable() {
    this.enabled = true;
  }

  @Override
  public void disable() {
    this.enabled = false;
  }

  @Override
  public Object accept(ComponentVisitor visitor) {
    return visitor.visit(this);
  }
}

这里有 2 个可能的复合根 (CompositeACompositeB) 和一个叶分量 ( Leaf)。

在这里,我定义了将保存序列化数据的 DTO:

class WholeCompositeASerialized {                     
  String content;                                     
  List<Object> serializedChildren;                    
}                                                     
                                                      
class WholeCompositeBSerialized{                      
  String content;                                     
  List<Object> serializedChildren;                    
}                                                     
                                                      
class WholeLeafSerialized{                            
  String content;                                     
}                                                     

现在,如果我使用访问者模式进行序列化,我会得到如下信息:

interface ComponentVisitor {
  WholeCompositeASerialized visit(CompositeA compositeA);
  WholeCompositeBSerialized visit(CompositeB compositeB);
  WholeLeafSerialized visit(Leaf leaf);
}

class SerializableComponentVisitor implements ComponentVisitor{
  @Override
  public WholeCompositeASerialized visit(CompositeA compositeA) {
    WholeCompositeASerialized wcas = new WholeCompositeASerialized();
    wcas.serializedChildren = compositeA
        .getComponents()
        .stream()
        .map(c -> c.accept(this))
        .collect(Collectors.toList());
    wcas.content = compositeA.getCompositeData();
    return wcas;
  }

  @Override
  public WholeCompositeBSerialized visit(CompositeB compositeB) {
    WholeCompositeBSerialized wcbs = new WholeCompositeBSerialized();
    wcbs.serializedChildren = compositeB
        .getComponents()
        .stream()
        .map(c -> c.accept(this))
        .collect(Collectors.toList());
    wcbs.content = String.valueOf(compositeB.getCompositeData());
    return wcbs;
  }

  @Override
  public WholeLeafSerialized visit(Leaf leaf) {
    WholeLeafSerialized wls = new WholeLeafSerialized();
    wls.content = Arrays.toString(leaf.getLeafData());
    return wls;
  }
}

interface Visitable{
  Object accept(ComponentVisitor visitor);
}

如果我使用instanceof这是做同样事情的代码:

class SerializerUsingInstanceOf {
  Object decide(Component component){
    if(component instanceof CompositeA){
      return serialize((CompositeA)component);
    }
    else if(component instanceof CompositeB){
      return serialize((CompositeB)component);
    }
    else{
      return serialize((Leaf)component);
    }
  }

  WholeCompositeASerialized serialize(CompositeA compositeA) {
    WholeCompositeASerialized wcas = new WholeCompositeASerialized();
    wcas.serializedChildren = compositeA
        .getComponents()
        .stream()
        .map(this::decide)
        .collect(Collectors.toList());
    wcas.content = compositeA.getCompositeData();
    return wcas;
  }

  WholeCompositeBSerialized serialize(CompositeB compositeB) {
    WholeCompositeBSerialized wcbs = new WholeCompositeBSerialized();
    wcbs.serializedChildren = compositeB
        .getComponents()
        .stream()
        .map(this::decide)
        .collect(Collectors.toList());
    wcbs.content = String.valueOf(compositeB.getCompositeData());
    return wcbs;
  }

  WholeLeafSerialized serialize(Leaf leaf) {
    WholeLeafSerialized wls = new WholeLeafSerialized();
    wls.content = Arrays.toString(leaf.getLeafData());
    return wls;
  }
}

                                                  

我猜这里还首选访问者,因为当我们添加 new 时Component,我们也需要实现Object accept(ComponentVisitor visitor)方法 - 所以我们不能忘记我们需要一个用于序列化这个新组件的代码。如果我们在使用时也这样做,instanceof我们可能会忘记将其添加到该检查中。

现在 - 我的问题是 - 有什么方法可以摆脱方法签名中那种丑陋的Object返回类型?Object accept(ComponentVisitor visitor)我想到的唯一其他选择是使用一些标记接口(例如。interface SerializedComponent {})然后让所有序列化程序类实现这样的空接口,class WholeCompositeASerialized implements SerializedComponent但它似乎仍然不正确。

标签: javaserializationdesign-patternscomposite

解决方案


我认为正确的方法可能是在这里使用泛型。

例如https://onlinegdb.com/r1m5Eg4DP

public class Main {

     public static void main(String []args){
        ComponentVisitor<SerializedComponent> serializer = new ComponentSerializer();
        Component componentA = new ComponentA();
        SerializedComponent serializedA = componentA.accept(serializer);
        System.out.println(serializedA);
        
        Component component = new ComponentB();
        SerializedComponent serializedB = component.accept(serializer);
        System.out.println(serializedB);
     }
     
     static interface Component {
        public <V> V accept(ComponentVisitor<V> visitor);
     }
     
     static class ComponentA implements Component {
        public <V> V accept(ComponentVisitor<V> visitor) {
            return visitor.visit(this);
        }
     }
     
     static class ComponentB implements Component {
         public <V> V accept(ComponentVisitor<V> visitor) {
            return visitor.visit(this);
         }
     }
     
     static interface SerializedComponent {}
     
     static class SerializedComponentA implements SerializedComponent {
     }
     
     static class SerializedComponentB implements SerializedComponent {
     }
     
     static interface ComponentVisitor<V> {
        public V visit(ComponentA component);
        public V visit(ComponentB component);
     }
     
     static class ComponentSerializer implements ComponentVisitor<SerializedComponent> {
        public SerializedComponent visit(ComponentA component) {
            return new SerializedComponentA();
        }
        public SerializedComponent visit(ComponentB component) {
            return new SerializedComponentB();
        }
     }
}

推荐阅读