Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/330.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_Enums_Interface_Dry_Weakhashmap - Fatal编程技术网

避免Java接口中的样板文件

避免Java接口中的样板文件,java,enums,interface,dry,weakhashmap,Java,Enums,Interface,Dry,Weakhashmap,我正试图用存储过程构建一个键值存储,我发现枚举在定义事物时非常方便。我希望DB是表的枚举,表与操作的枚举和区域的枚举相关联。问题是枚举不能扩展抽象类,所以我必须使用接口。所以我有很多枚举,每个枚举都必须实现相同的代码(定义相同的字段,编写相同的构造函数来填充这些字段,并重写使用这些字段的getter和方法)。下面是这样一个枚举的示例: interface Operation<VAL, PARAM> { int code(); Serdes<PARAM> p

我正试图用存储过程构建一个键值存储,我发现枚举在定义事物时非常方便。我希望DB是表的枚举,表与操作的枚举和区域的枚举相关联。问题是枚举不能扩展抽象类,所以我必须使用接口。所以我有很多枚举,每个枚举都必须实现相同的代码(定义相同的字段,编写相同的构造函数来填充这些字段,并重写使用这些字段的getter和方法)。下面是这样一个枚举的示例:

interface Operation<VAL, PARAM>
{
    int code();
    Serdes<PARAM> pSerdes();
    VAL apply(VAL val, byte[] pbytes);
}

...

// Job, Param, & Ticket are protobuf classes
public enum JobOp implements Operation<Job, Param>
{
    AddTicket(0, (job, param) -> ...),
    RemoveTicket(1, (job, param) -> ...),
    CompleteTicket(2, (job, param) -> ...);

    private final int code;
    private final Serdes<Param> pSerdes = new ProtoSerdes<>(Param.PARSER);
    private final BiFunction<Job, Param, Job> proc;
    JobOp(int code, BiFunction<Job, Param, Job> proc)
    {
        this.code = code
        this.proc = proc
    }

    @Override
    public int code() { return code; }
    @Override
    public Serdes<Param> pSerdes() { return pSerdes; }
    @Override
    public Job apply(Job val, byte[] pbytes)
    {
        final Param param = pSerdes.fromBytes(pbytes);
        return proc.apply(val, param);
    }
}
接口操作
{
int代码();
Serdes pSerdes();
VAL apply(VAL-VAL,字节[]PB);
}
...
//Job、Param和Ticket是protobuf类
公共枚举作业执行操作
{
AddTicket(0,(作业,参数)->…),
拆卸工具(1,(作业,参数)->…),
CompleteTicket(2,(作业,参数)->…);
私有最终整数码;
private final Serdes pSerdes=新的ProtoSerdes(Param.PARSER);
专用最终双功能程序;
JobOp(整数代码,双功能程序)
{
this.code=代码
this.proc=proc
}
@凌驾
public int code(){return code;}
@凌驾
public Serdes pSerdes(){return pSerdes;}
@凌驾
公共作业应用(作业值,字节[]PB)
{
final Param Param=pSerdes.fromBytes(PB字节);
返回过程应用(val,参数);
}
}
我希望避免所有重复的样板文件,并尽可能尊重DRY,因此我开始使用内部类来表示字段:

interface Operation<VAL, PARAM>
{
    default int code() { return imp().code; }
    default Serdes<PARAM> pSerdes() { return imp().pSerdes; }
    default VAL apply(VAL val, byte[] pbytes) { return imp().apply(val, pbytes); }
    // Reduce the number of fields and getters to implement to one: imp
    Imp<VAL, PARAM> imp();

    class Imp<VAL, PARAM>
    {
        public final int code;
        public final Serdes<PARAM> pSerdes;
        private final BiFunction<V, P, V> proc;

        Imp(int code, Serdes<PARAM> pSerdes, BiFunction<V, P, V> proc)
        {
            this.code = code;
            this.pSerdes = pSerdes;
            this.proc = proc;
        }

        VAL apply(VAL val, byte[] pbytes)
        {
            PARAM param = pSerdes.fromBytes(pbytes);
            return proc.apply(val, param);
        }
    }
}

...

// Job, Param, & Ticket are protobuf classes
public enum JobOp implements Operation<Job, Param>
{
    AddTicket(0, (job, param) -> ...),
    RemoveTicket(1, (job, param) -> ...),
    CompleteTicket(2, (job, param) -> ...);

    private final Serdes<Param> pSerdes = new ProtoSerdes<(Param.PARSER);
    private final Operation.Imp<Job, Param> imp;
    JobOp(int code, BiFunction<Job, Param, Job> proc)
    {
        imp = new Imp(code, pSerdes, proc);
    }

    @Override
    public Imp<Job, Param> imp() { return imp; }
}
接口操作
{
默认int code(){return imp().code;}
默认Serdes pSerdes(){return imp().pSerdes;}
默认值应用(VAL-VAL,字节[]pbytes){return imp().apply(VAL,pbytes);}
//将要实现的字段和getter的数量减少到一个:imp
Imp Imp();
类Imp
{
公共最终int代码;
公共最终服务;
专用最终双功能程序;
Imp(int代码、Serdes pSerdes、双功能程序)
{
this.code=代码;
this.pSerdes=pSerdes;
this.proc=proc;
}
VAL应用(VAL VAL,字节[]PB)
{
PARAM PARAM=pSerdes.fromBytes(PB字节);
返回过程应用(val,参数);
}
}
}
...
//Job、Param和Ticket是protobuf类
公共枚举作业执行操作
{
AddTicket(0,(作业,参数)->…),
拆卸工具(1,(作业,参数)->…),
CompleteTicket(2,(作业,参数)->…);
私人最终协议=新协议,
拆卸工具(1,(作业,参数)->…),
CompleteTicket(2,(作业,参数)->…);

private final Serdes pSerdes=new ProtoSerdes为此使用父类有什么问题?使用以下方法代替接口操作:

public abstract class Operation<VAL, PARAM> {
    private int code;

    public int getCode() { return code; }
    public abstract void example();
}
公共抽象类操作{
私有整数码;
public int getCode(){return code;}
公共抽象无效示例();
}
…然后从那里开始

与接口不同,类可以有状态。在上面的示例中,
getCode
将使用所述的实现,但如果愿意,您可以覆盖它(您可以添加
final
作为关键字来停止该操作),方法
example
必须由子类实现。它类似于接口中的普通
void example();
(在接口中,默认情况下,所有方法声明都是公共和抽象的,在类中,您必须添加这些关键字)


如果它不能成为一个超类,这不是一个好主意;一般的概念是接口真的不应该有状态。如果你坚持要有状态接口,你或多或少会犯一些低级错误。

你是在设计一个什么都懂、什么都能执行的God类吗?

可能会将任务划分为多个部分并将其组装起来以执行。

抽象类的问题在于不能将它们与枚举一起使用。我不是在设计God类。可能我在示例中选择的
操作
类会造成混乱。我主要是想回避这样一个事实,即枚举只允许您在我想要一个扩展抽象类的枚举,以避免重复定义相同的字段、编写相同的构造函数以及反复重载相同的getter。我希望我的KV存储中的每个表都有一个与其相关联的操作枚举和一个区域枚举。我也不希望DB成为表枚举。这样做e是很难的。正如您提到的DB和Tables,为什么不使用或参考JPA、Spring AOP、Spring事务管理?Java注释和反射是它们的核心技术。
public abstract class Operation<VAL, PARAM> {
    private int code;

    public int getCode() { return code; }
    public abstract void example();
}