这段代码是否违反开闭原则?
Does this code violate open-closed principle?
我想知道下面的代码是否违反了开闭原则。
Animal
是 Dog
的父级 class,但是 Animal
具有有助于 ObjectMapper
(反)序列化 class 的杰克逊注释]是的。任何扩展 Animal
的人都必须只编辑 Animal
上的注释,以确保(反)序列化按预期工作,而 class 保持不变。
@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 {
}
理论观点
Open/closed principle like the whole SOLID 是 Utopia
。我们应该朝那个方向不断升级我们的代码,但我们可能永远不会在那里结束,因为这是不可能的。让我们阅读下面的文章,看看 classical getters
和 annotation
结构如何值得商榷。
实用观点
像每个实用的程序员一样,我喜欢使用好的工具来解决问题,而不是自己实现新的东西。当我被要求将给定模型序列化为 JSON
文件时,我正在检查它是否是:
- 开源
- 快
- 正在积极开发中
- 易于使用
当我们谈论 Jackson
及其注释时,我认为,我们可以找到理论与实践之间的黄金中间道路。这要归功于 MixIn
功能。您可以将模型与其序列化为 JSON
的方式分开。当然,当你添加新的 class 扩展基础 class 时,你需要用注释更改 MixIn
interface
但这是我们需要付出的代价。
编辑或为什么我忘了回答问题?
抱歉,我忘了回答一个问题,上面的例子是否违反了Open/Closed principle
。首先,从 Wikipedia
article:
获取定义
A class is closed, since it may be compiled, stored in a library,
baselined, and used by client classes. But it is also open, since any
new class may use it as parent, adding new features. When a descendant
class is defined, there is no need to change the original or to
disturb its clients.
上面的例子违反了When a descendant class is defined, there is no need to change the original
部分。即使我们使用 MixIn
也需要更改应用程序的其他部分。更重要的是,如果你的解决方案在 99.99% 的情况下使用 annotations
,你就违反了这一部分,因为需要以某种方式配置隐藏在它们后面的功能。
确实如此。 open-close 原则的想法是使 objects 可扩展,而无需在内部修改它们。由于 Animal
的任何新 child 都必须对其进行修改才能正常工作,这违反了原则。
Open/closed 表示 class 应该对扩展开放,但对修改关闭。
换句话说...如果您想更改 class 的行为,您应该以某种方式扩展它,但不应该修改它。
您可以 class 扩展
- 创建子class。这通常使用例如模板方法模式。
- 定义一个 class A 使用的接口,这样它的行为就可以通过传递该接口的另一个实例来扩展,例如一种策略模式。
TreeSet(Comparator<? super E> comparator)
是一个很好的现实生活示例,因为它的排序行为可以在不修改 TreeSet
本身的情况下进行更改。
从我的角度来看,@JsonSubTypes
注释不是 Animal
class 行为的一部分。它改变了另一个 class - 对象映射器的行为。因此,这并不是真正的违规行为。不是真的意味着即使你不改变行为,你也必须触摸 Animal
class 并重新编译它。
注解的设计真是奇葩。为什么 json 开发人员不允许您在子 class 上添加注释,例如就像 JPA 在层次结构映射方面所做的那样。参见 DiscriminatorValue
超类型引用子类型是一个奇怪的设计。
抽象类型不应依赖于具体类型。在我看来,这是一个应该始终应用的原则。
我想知道下面的代码是否违反了开闭原则。
Animal
是 Dog
的父级 class,但是 Animal
具有有助于 ObjectMapper
(反)序列化 class 的杰克逊注释]是的。任何扩展 Animal
的人都必须只编辑 Animal
上的注释,以确保(反)序列化按预期工作,而 class 保持不变。
@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 {
}
理论观点
Open/closed principle like the whole SOLID 是 Utopia
。我们应该朝那个方向不断升级我们的代码,但我们可能永远不会在那里结束,因为这是不可能的。让我们阅读下面的文章,看看 classical getters
和 annotation
结构如何值得商榷。
实用观点
像每个实用的程序员一样,我喜欢使用好的工具来解决问题,而不是自己实现新的东西。当我被要求将给定模型序列化为 JSON
文件时,我正在检查它是否是:
- 开源
- 快
- 正在积极开发中
- 易于使用
当我们谈论 Jackson
及其注释时,我认为,我们可以找到理论与实践之间的黄金中间道路。这要归功于 MixIn
功能。您可以将模型与其序列化为 JSON
的方式分开。当然,当你添加新的 class 扩展基础 class 时,你需要用注释更改 MixIn
interface
但这是我们需要付出的代价。
编辑或为什么我忘了回答问题?
抱歉,我忘了回答一个问题,上面的例子是否违反了Open/Closed principle
。首先,从 Wikipedia
article:
A class is closed, since it may be compiled, stored in a library, baselined, and used by client classes. But it is also open, since any new class may use it as parent, adding new features. When a descendant class is defined, there is no need to change the original or to disturb its clients.
上面的例子违反了When a descendant class is defined, there is no need to change the original
部分。即使我们使用 MixIn
也需要更改应用程序的其他部分。更重要的是,如果你的解决方案在 99.99% 的情况下使用 annotations
,你就违反了这一部分,因为需要以某种方式配置隐藏在它们后面的功能。
确实如此。 open-close 原则的想法是使 objects 可扩展,而无需在内部修改它们。由于 Animal
的任何新 child 都必须对其进行修改才能正常工作,这违反了原则。
Open/closed 表示 class 应该对扩展开放,但对修改关闭。
换句话说...如果您想更改 class 的行为,您应该以某种方式扩展它,但不应该修改它。
您可以 class 扩展
- 创建子class。这通常使用例如模板方法模式。
- 定义一个 class A 使用的接口,这样它的行为就可以通过传递该接口的另一个实例来扩展,例如一种策略模式。
TreeSet(Comparator<? super E> comparator)
是一个很好的现实生活示例,因为它的排序行为可以在不修改TreeSet
本身的情况下进行更改。
从我的角度来看,@JsonSubTypes
注释不是 Animal
class 行为的一部分。它改变了另一个 class - 对象映射器的行为。因此,这并不是真正的违规行为。不是真的意味着即使你不改变行为,你也必须触摸 Animal
class 并重新编译它。
注解的设计真是奇葩。为什么 json 开发人员不允许您在子 class 上添加注释,例如就像 JPA 在层次结构映射方面所做的那样。参见 DiscriminatorValue
超类型引用子类型是一个奇怪的设计。 抽象类型不应依赖于具体类型。在我看来,这是一个应该始终应用的原则。