如何编写一个类来支持它所代表的结构的多个版本?

时间:2010-07-16 17:18:41

标签: java

假设我想要一个代表内存中数据结构的类。在此结构中,前两个字节表示它的结构版本。以下数据的顺序和大小取决于结构的版本。

例如: 版本1是一个10字节的结构,如下所示:

  • 字节偏移0:格式版本(2 字节)
  • 字节偏移2:数据部分A. (4个字节)
  • 字节偏移6:数据部分 B(4字节)

版本2是一个20字节的结构,如下所示:

  • 字节偏移量0:格式化版本(2个字节)
  • 字节偏移2:数据部分A(8字节)
  • 字节偏移10:数据部分B(6字节)
  • 字节偏移16:数据部分C(4字节)

我希望我的类能够支持这两个版本,而不必让类的用户指定要使用的版本。也就是说,当构造对象时,它应该能够使用Format Version字段来确定其结构应该是什么。然后,应根据结构适当地创建每个字段的getter / setter。我还希望将来能够添加对其他结构版本的支持。每个新版本的结构很可能包含与旧版本相同的所有字段,但可能每个字段的分配长度更长,也许还有一些新添加的字段。

据我所知,我唯一的限制是格式版本字段总是出现在字节偏移0处,并且总是2个字节长。

那么,有可能实现我的目标吗?

3 个答案:

答案 0 :(得分:6)

通常,您将为每个不同版本的结构创建和使用单独的类。您可以为它们提供一个通用接口,以便您可以通过常见类型进行寻址和存储。那些不同的结构类可以包含不同的字段和方法来处理数据的不同变化。

// The common interface. Every struct knows how to read and write itself.
public interface MultiStruct {
  public void readData(InputStream in);
  public void writeData(OutputStream out);
}

// This class knows only about storing a format code
public abstract class AbstractMultiStruct implements MultiStruct {
  protected static final int FORM1 = 1, FORM2 = 2;

  private int format;

  public AbstractMultiStruct(int fmt) {
    this.format = fmt;
  }

  public int getFormat() {
    return this.format;
  }

}

// This is the first real struct implementation.
public class Struct1 extends AbstractMultiStruct {
  private char[] dataA;
  private char[] dataB;

  public Struct1() {
    super(FORM1);
    this.dataA = new char[22];
    this.dataB = new char[33];
  }

  public void readData(InputStream in) {
    ...
  }

  public void writeData(OutputStream out) {
    ...
  }

  public String toString() {
    ...
  }


}

答案 1 :(得分:2)

我认为你需要一个类层次结构。为结构实现的概念创建一个抽象类。该类具有逻辑(比如静态方法),通过检查版本字段从数据构造具体类。然后,抽象类根据数据实例化Version1类或Version2类。

抽象类仅包含版本字段。 Version1子类包含版本1字段。版本2子类包含版本2字段。由于这两个版本非常不同,因此版本1和版本2都来自基类。如果版本2是版本1的扩展,那么您将使用Version2类扩展Version1类。

E.g。

abstract class MyStructure
{
   static public MyStructure create(DataInputStream data) {
      int version = data.readShort();
      MyStructure structure;
      if (version==1)
         structure = new MyStructure1();
      else if (version==2)
          structure = new Mystructure2();
      else
         throw IllegalArgumentException("unkonwn version "+version);
      structure.read(data);
      return structure;
   }

   abstract protected void read(DataInputStream input) throws IOException;

   // accessors for the common sections, either as raw data
   public abstract byte[] getSectionA();
   // or as primitive types, 
   public abstract long getSectionA();
   // or with it's own class
   public abstract SectionA getSectionA();

}

class MyStructureVersion1 extends MyStructure
{
    // fields for version 1
    int a;
    int b;

    protected void read(DataInputStream input) throws IOException { 
      // read fields from input
      a = input.readInt();
      b = input.readInt();
    }

    public long getSectionA() {
        return a;
    }
}


class MyStructureVersion2 extends MyStructure
{
    // fields for version 2, could be primitives, byte arrays 
    // or SectionA, SectionB objects
    long a;
    long b;
    int c;
    protected void read(DataInputStream input) throws IOException { 
      // read fields from input
      a = input.readLong();
      b = input.readLong();
      c = input.readInt();
    }

    pubic long getSectionA() {
        return a;
    }
}

答案 2 :(得分:0)

通常,您将创建一个知道如何解释格式版本字节的类,并返回提供对数据访问的类的正确实现。这些实现应共享一个公共基类。一个非常简单的例子:

public abstract class MyData {
  protected byte[] data;

  MyData(byte[] data) {
    this.data = data;
  }

  public abstract WhatEver getInformation();
}

public class MyDataA extends MyData {

  MyDataA(byte[] data) {
    super(data);
  }

  public WhatEver getInformation() {
    //extract data from the correct offset for format a
    //in the data field of the base class
  }
}

public class MyDataB extends MyData {

  MyDataB(byte[] data) {
    super(data);
  }

  public WhatEver getInformation() {
    //extract data from the correct offset for format b
    //in the data field of the base class
  }
}

public class MyDataFactory {

  public MyData createMyData(byte[] data) {
    if ( first 2 bytes indicate format a ) {
      return new MyDataA(data);
    } else if (first 2 bytes indicate format b) {
      return new MyDataB(data);
    }
  }

}