Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/312.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 部分可变的API类,带有通用变量保持器供客户端使用_Java_Api_Design Patterns_Immutability - Fatal编程技术网

Java 部分可变的API类,带有通用变量保持器供客户端使用

Java 部分可变的API类,带有通用变量保持器供客户端使用,java,api,design-patterns,immutability,Java,Api,Design Patterns,Immutability,我正在构建一个API。它的一个功能是执行一些资源分析(想象一个文档、URI或DB,不重要的是什么)并返回一个列表,其中Finding是一个POJO。我希望Finding在从API返回时是不可变的,所有数据都是由API返回的,但是,为了方便客户端,我希望有一个setUserNote(String)方法 这样做的原因是,客户机可以获得查找s的列表,它可以在使用setUserNote将自己的数据保存在对象本身中时处理这些列表,就像普通的注释一样。我认为这比客户机必须扩展Finding来添加一个变量或将

我正在构建一个API。它的一个功能是执行一些资源分析(想象一个文档、URI或DB,不重要的是什么)并返回一个
列表,其中
Finding
是一个POJO。我希望
Finding
在从API返回时是不可变的,所有数据都是由API返回的,但是,为了方便客户端,我希望有一个
setUserNote(String)
方法

这样做的原因是,客户机可以获得
查找
s的列表,它可以在使用
setUserNote
将自己的数据保存在对象本身中时处理这些列表,就像普通的注释一样。我认为这比客户机必须扩展
Finding
来添加一个变量或将其封装为实例变量,然后
ExtendedFinding.someMethod(){返回this.Finding.someMethid();}
来查找
中的每个方法更方便。此外,至少可以说,对于客户机来说,用他从API获得的
查找
来构造
扩展查找
,会很麻烦。这就是为什么我计划只给他们一个方便使用的领域

问题:

  • 这是一个糟糕的设计吗?为什么?我以前从未做过类似的事情,也没有见过API类为了方便客户机而附带任意数据保持器变量

  • 假设这是一个糟糕的设计。什么是一种适用的设计模式,可以方便地传播查找以构建客户端的ExtendedFinding?当然,您可以使用类似public
    ExtendedFinding(Finding){/*copy vars one-by-one*/}
    的东西,但这远远不够优雅


  • 这不一定是糟糕的设计。这听起来很少见。在设计API时,务必牢记API的可能用途,但我觉得这有点过分了:

    • 它打破了单一责任原则:该类现在既可以表示
      发现
      ,也可以作为用户指定数据的容器
    • 它将用户限制为
      String
      notes,而不是任意对象。例如,如果需要,他们将无法使用地图或自定义POJO。(不过,使用泛型可以很容易地解决这个问题。)
    更好的解决方案可能是在
    Finding
    类中定义
    equals
    hashCode
    方法。通过这种方式,这些对象可以用作
    映射的键,用户可以将其注释存储在API之外

    另一种解决方案可能是定义一个新类来表示
    查找
    和用户注释对。这比在不可变的
    查找
    类中存储注释有更清晰的“感觉”,但增加的复杂性可能使其不值得付出努力。哪种解决方案最好实际上取决于具体情况;答案没有对错之分


    (顺便说一句,
    final
    关键字并没有使类不可变。它只是意味着你不能为它定义子类。你可以创建可变的final类——举个例子)

    首先你的第三点,
    final
    决不能使类不可变——它意味着类不能从中继承。因此,您不能
    扩展
    final

    对于您的主要问题,为什么不将POJO强制转换为
    接口
    ,并返回该接口的列表,而不是底层POJO。然后,您可以将实际的POJO类包设置为私有,以便客户端无法将其回滚:

    public static interface Finding {
        //all public getters
    
        void setUserNote();
    }
    
    static final class FindingImpl implements Finding {
    
        @Override
        public void setUserNote() {
            throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
        }
    }
    private final Collection<FindingImpl> findingImpls = new ArrayList<>();
    
    public Collection<Finding> getFindings() {
        final Collection<Finding> findings = new ArrayList<>();
        for (final FindingImpl fi : findingImpls) {
            findings.add(fi);
        }
        return findings;
    }
    
    公共静态接口查找{
    //所有公众人物
    void setUserNote();
    }
    静态最终类FindingImpl实现查找{
    @凌驾
    public void setUserNote(){
    抛出新的UnsupportedOperationException(“尚未受支持”);//若要更改生成的方法体,请选择“工具”“模板”。
    }
    }
    private final Collection findingpimpls=new ArrayList();
    公众收集{
    最终收集结果=新的ArrayList();
    对于(最终FindingImpl fi:findingImpls){
    调查结果。添加(fi);
    }
    返回结果;
    }
    
    我很困惑。如果你把一个发现归还给我,你认为不可改变的话,那我怎么能给这个物体注入一个音符呢?假设其他人也会看到同样的发现,不是吗

    这里的正确答案是,您应该有另一个类:FindingComment,带有注释者id、查找id和时间戳


    你的直觉是,扩展类来吸引评论肯定是正确的

    听起来像是
    userNote
    不应该在
    Finding
    中。但我仍然想知道这是否是一种反模式(用户便利数据包变量,其中所有其他类变量都是只读的)。当然,
    String
    只是为了简单起见。它可能是一个
    对象
    或者是你的第一个项目的一些集合,注释肯定是这个发现的一个属性,类似于用户添加的附录。有点像你买了一本参考手册,它的末尾有10页空白供你输入你自己的笔记。是的,我没有回答这个易变的问题。对不起,我对
    最终版
    感到困惑。我假设
    查找
    中的每个变量都需要声明为final,但usernote除外我不明白为什么-如果最终用户由于
    接口
    (所有变量都是
    私有的
    )而只能访问getter而不能访问setter,那么就没有理由将变量设置为final
    。这是调用封装。