此代码是否违反开闭原则?

时间:2019-02-15 16:04:48

标签: java oop design-patterns jackson jackson-databind

我想知道以下代码是否违反开放封闭原则。

AnimalDog的父类,但是Animal具有杰克逊注释,可帮助ObjectMapper(反序列化)这些类。扩展Animal的任何人都只需要编辑Animal上存在的注释,以确保(反)序列化能够按预期工作,而不会影响类。

@JsonTypeInfo(
  use = JsonTypeInfo.Id.NAME, 
  include = JsonTypeInfo.As.PROPERTY, 
  property = "type")
@JsonSubTypes({ 
  // all subclasses
  @Type(value = Dog.class, name = "dog")
})
public abstract class Animal {
    // fields, constructors, getters and setters
}

public class Dog extends Animal {

}

3 个答案:

答案 0 :(得分:2)

确实如此。开闭原理的思想是使对象可扩展,而无需在内部进行修改。由于Animal的任何新子级都必须对其进行修改才能正常工作,因此这违反了原理。

答案 1 :(得分:0)

理论观点

Open/closed principle就像整个SOLIDUtopia。我们应该朝那个方向不断地升级我们的代码,但是可能我们永远都不会结束,因为这是不可能的。让我们阅读下面的文章,看看经典的gettersannotation构造如何值得商

  1. Printers Instead of Getters
  2. Java Annotations Are a Big Mistake

实用的观点

像每个实际的程序员一样,我喜欢使用好的工具来解决问题,而不是自己实现新功能。当要求我将给定模型序列化为JSON文件时,我正在检查它是否是:

  1. 开源
  2. 快速
  3. 积极发展中
  4. 易于使用

我认为,当我们谈论Jackson及其注释时,我们可以找到理论与实践之间的黄金中间道路。这要归功于MixIn功能。您可以将模型与序列化为JSON的方式分开。当然,当您添加扩展基类的新类时,您需要使用注释更改MixIn interface,但这是我们需要付出的代价。

编辑还是为什么我忘记回答问题?

对不起,我忘记回答一个问题,上述示例是否违反了Open/Closed principle。首先,从Wikipedia article获取定义:

  

一个类是封闭的,因为它可以被编译,存储在库中,   基准化,并由客户端类使用。但这也是开放的,因为任何   新类可以将其用作父类,从而增加新功能。当子孙   类已定义,无需更改原始或   打扰客户。

以上示例违反了When a descendant class is defined, there is no need to change the original部分。即使我们使用MixIn,也需要更改应用程序的其他部分。更重要的是,如果您的解决方案在99.99%的情况下使用annotations,则您违反了此部分,因为需要配置某种隐藏在其后面的功能。

答案 2 :(得分:0)

打开/关闭意味着应该打开一个类以进行扩展,但是关闭以进行修改。

换句话说,如果您想更改类的行为,则应该以某种方式扩展它,但不要修改它。

您可以通过

扩展课程
  • 创建一个子类。通常使用例如模板方法模式。
  • 定义类A使用的接口,以便可以通过将其传递给该接口的另一个实例来扩展其行为,例如战略模式。现实生活中的一个好例子是TreeSet(Comparator<? super E> comparator),因为无需更改TreeSet本身就可以更改其排序行为。

从我的角度来看,@JsonSubTypes注释不是Animal类的行为的一部分。它更改了另一个类的行为-对象映射器。因此,这并不是真正的违反。并不是说即使您不更改行为,也必须触摸Animal类并重新编译它。

这是一个非常奇怪的注释设计。为什么json开发人员不允许您在子类上添加注释,例如就像JPA在层次结构映射中所做的一样。参见DiscriminatorValue

超类型引用子类型是一个奇怪的设计。 抽象类型不应依赖于具体类型。我认为这是应始终适用的原则。