简体   繁体   English

抽象超类的抽象方法作为子类中的静态方法

[英]Abstract method from an abstract superclass as a static method within the subclass

I have developed a custom communication protocol. 我已经开发了一个自定义的通信协议。 In this protocol each packet is made up of a header and a payload. 在此协议中,每个数据包均由标头和有效载荷组成。 Each payload contains multiple commands. 每个有效负载包含多个命令。

I'd like to implement a static 'decode' method within every Command (Command0, ..., Command N) because all commands of the same type are decoded the same way (they have the same field structure). 我想在每个Command(Command0,...,Command N)中实现一个静态的“ decode”方法,因为相同类型的所有命令都以相同的方式解码(它们具有相同的字段结构)。 I use an abstract class 'Command' as a template with some common fields and methods and an abstract 'decode' method for my commands. 我使用抽象类“ Command”作为模板,其中包含一些常见的字段和方法,以及用于命令的抽象“ decode”方法。 But since the superclass method is abstract, the 'decode' method within Command0, ..., CommandN can't be static. 但是由于超类方法是抽象的,因此Command0,...,CommandN中的“解码”方法不能是静态的。

Any workaounds? 有麻烦吗? I'd like to avoid instantiating every command each time I have to decode some packet. 我想避免每次必须解码某些数据包时都实例化每个命令。

As an alternative I've got rid of the abstract 'decode' method and included a static 'decode' method within every command extending Command. 作为一种替代方案,我摆脱了抽象的“ decode”方法,并在扩展Command的每个命令中都包含一个静态的“ decode”方法。 However, without a superclass or an interface, another programmer could forget to implement a decode method. 但是,如果没有超类或接口,则另一个程序员可能会忘记实现解码方法。 This alternative would lead to the following code: 此替代方法将导致以下代码:

{
    switch(commandIdentifier)
    {
        case 0:
        {
            Command0 command0 = Command0.decode(dbConnection, header, data, offset);
            payload.getCommands().add(command0);
            break;
        }
        //...
        case N:
        {
            CommandN commandN = CommandN.decode(dbConnection, header, data, offset);
            payload.getCommands().add(commandN);
            break;
        }
        default:
        {
            //some code
        }
    }
}

Where I first have to check the command identifier. 我首先必须检查命令标识符。

I have originally implemented the classes this way: 我最初以这种方式实现了这些类:

public class Packet
{
    private Header header;
    private Payload payload;

    public static Packet decode(Connection dbConnection, byte[] data, int offset) throws Exception
    {
        //...
    }
}

public class Header
{
    public static Header decode(byte[] data, int offset)
    {
        //...
    }
}

public class Payload
{
    private List<Command> commands;
    public static Payload decode(Connection dbConnection, Header header, byte[] data, int offset)
    {
        //iterate over the data bytes to populate commands
    }
}

public abstract class Command
{
    public abstract Command decode(Connection dbConnection, Header header, byte[] data, int offset) throws Exception;
}

public class Command0
{
    int field1;
    String field2;
    float field3;
    public Command decode(Connection dbConnection, Header header, byte[] data, int offset) throws Exception;  //I can't make it static and I'd like to because all commands of class Command0 are decoded the same way.
}

//...

public class Command N
{
    int field1;
    Map<Integer, ConfigBean> field2;
    public Command decode(Connection dbConnection, Header header, byte[] data, int offset) throws Exception;  //I can't make it static and I'd like to because all commands of class CommandN are decoded the same way.
}

You could have an enum class that contains the info relative to what command is and how to decode it. 您可能有一个enum类,其中包含有关什么命令以及如何对其进行解码的信息。 Using an abstract method instead of a static methid will force you to implement a decode for each one: 使用抽象方法而不是静态方法将迫使您为每个方法实现解码:

public enum CommandType {
    COMMAND_0(0) {
        @Override
        public <T extends Command> T decode(Connection dbConnection, ResponseBuilder.Header header, byte[] data, int offset) throws Exception {
            // decode Command 0
            ...
        }
    },
    COMMAND_1(1) {
        @Override
        public <T extends Command> T decode(Connection dbConnection, ResponseBuilder.Header header, byte[] data, int offset) throws Exception {
            // decode Command 1
            ...
        }
    }
    ...
    COMMAND_N(N) {
        @Override
        public <T extends Command> T decode(Connection dbConnection, ResponseBuilder.Header header, byte[] data, int offset) throws Exception {
            // decode Command N
            ...
        }
    }
    ;

    private final int commandIdentifier;

    CommandType(int commandIdentifier) {
        this.commandIdentifier = commandIdentifier;
    }

    public abstract <T extends Command> T decode(Connection dbConnection, ResponseBuilder.Header header, byte[] data, int offset) throws Exception;


    private static Map<Integer, CommandType> map = new HashMap<Integer, CommandType>();
    static {
        for (CommandType commandType : CommandType.values()) {
            if (map.get(commandType.commandIdentifier) != null)
                throw new IllegalStateException("There are several commands with the same identifier");
            map.put(commandType.commandIdentifier, commandType);
        }
    }

    public static CommandType fromIdentifier(int commandIdentifier) throws IllegalArgumentException {
        CommandType commandType = map.get(commandIdentifier);
        if (commandType == null)
            throw new IllegalArgumentException("Unkown command identifier");
        return commandType;
    }

}

After that you can simply use: 之后,您可以简单地使用:

Command c = CommandType.fromIdentifier(commandIdentifier).decodedecode(dbConnection, header, data, offset);

I think that's a more stylish way of handling this 我认为这是一种更时尚的处理方式

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM