Java 如何处理抽象类作为微服务的入口api契约,同时处理多态性?
我正在学习十几个教程,这些教程对我来说几乎没有什么帮助,因为生产代码不是动物、鸟类或人类。这不是一种切割或射击类型的武器,它的推理要复杂得多 回到现实,情景: 服务1通过Kafka与服务2交换消息,消息通过Jackson序列化/反序列化,模型类作为jar在服务之间共享 现在,瘟疫部分,邪恶的顶点:Java 如何处理抽象类作为微服务的入口api契约,同时处理多态性?,java,spring,polymorphism,microservices,Java,Spring,Polymorphism,Microservices,我正在学习十几个教程,这些教程对我来说几乎没有什么帮助,因为生产代码不是动物、鸟类或人类。这不是一种切割或射击类型的武器,它的推理要复杂得多 回到现实,情景: 服务1通过Kafka与服务2交换消息,消息通过Jackson序列化/反序列化,模型类作为jar在服务之间共享 现在,瘟疫部分,邪恶的顶点: @JsonTypeInfo( use = Id.NAME, property = "type", visible = true ) @J
@JsonTypeInfo(
use = Id.NAME,
property = "type",
visible = true
)
@JsonSubTypes({@Type(
value = InternalTextContent.class,
name = "text"
), @Type(
value = InternalImageContent.class,
name = "image"
), @Type(
value = InternalAudioContent.class,
name = "audio"
), @Type(
value = InternalCustomContent.class,
name = "custom"
)})
public abstract class InternalContent {
@JsonIgnore
private ContentType type;
public InternalContent() {
}
显然,当开始使用此内容时,我们将有如下内容:
message.getInternalContent
这将导致大量的开关
语句,如果
条件,实例
并等待它。。。到处低落
这只是包装对象包含的一个属性示例。显然,我不能将多态行为添加到InternalContent,因为它在一个jar中
这里出了什么问题?这是错误的吗?
如何添加多态行为?要添加一个新的缓解层,我仍然需要在一些工厂中创建一个新类型的多态对象族,该族可编辑以添加所需的行为?甚至不确定它是否会更好,它只是让我感觉到并想射杀那些抛出像instanceof
这样的盲目声明的拥护者“折磨像我这样真心关心的人,这让我怀疑他们是否曾参与过真正的项目。我特意添加了系统环境细节,以了解如何不仅对代码建模,而且对系统之间的交互进行建模。实现“按书”解决方案的可能重新设计选项有哪些
到目前为止,我认为共享域模型是一种罪恶。但是,如果我使用不同的自服务包含类来表示相同的序列化/反序列化,我会获得灵活性,但会失去契约,增加不可预测性。从技术上讲,HTTP契约就是这样
我是否应该沿线路发送具有不同结构的不同类型的消息,而不是尝试在单个消息类型中为不常见的消息匹配公共部分和子类型
为了在OO扔更多的沙子,我认为Pivotal是迄今为止最好的:
公共布尔支持(类身份验证){
返回(UsernamePasswordAuthenticationToken.class)
.isAssignableFrom(身份验证));
}
AuhenticationManager有一个这样的AuthenticationProviders列表,并根据上述方法选择正确的一个。这违反多态性吗?有时候,这一切只是一种炒作……使用访客模式 示例(我将限制为两个子类,但您应该知道):
接口内部contentvisitor{
T visitText(内部文本内容c);
T访问量(内部图像内容c);
}
公共抽象类内容{
公共摘要不可接受(内部内容访问者);
// ...
}
公共类内部文本内容{
@凌驾
公共不接受(内部内容访问者){
return visitor.visitext(本);
}
}
公共类内部图像内容{
@凌驾
公共不接受(内部内容访问者){
访客回访(本);
}
}
这段代码是完全通用的,可以由使用这些类的任何应用程序共享
现在,如果您想在project1中使用InternalContent以多态方式执行某些操作,那么您所需要做的就是创建一个访问者。该访问者不属于InternalContent类,因此可以包含特定于project1的代码。例如,假设project1有一个类Copier,可用于创建文本或图像的副本,您可以使用
InternalContent content = ...; // you don't know the actual type
Copier copier = new Copier();
Copy copy = content.accept(new InternalContentVisitor<Copy>() {
@Override
public Copy visitText(InternalTextContent c) {
return copier.copyText(c.getText());
}
@Override
public Copy visitImage(InternalImageContent c) {
return copier.copyImage(c.getImage());
}
});
InternalContent=…;//你不知道真正的类型
复印机复印机=新复印机();
Copy Copy=content.accept(新的InternalContentVisitor(){
@凌驾
公共副本visitText(内部文本内容c){
返回copier.copyText(c.getText());
}
@凌驾
公共副本访问(InternalImageContent c){
返回copier.copyImage(c.getImage());
}
});
因此,正如您所看到的,不需要开关箱。尽管InternalContent类及其子类完全不依赖于仅存在于project1中的Copier类,但一切仍然是以多态方式完成的
如果出现一个新的
InternalSoundContent
类,您所要做的就是在访问者界面中添加一个visitSound()
方法,并在该界面的所有实现中实现它。Google for the visitor模式。这就是使用多态性的方法,避免instanceof,并且在共享类之外仍然有多态性调用的代码。@JBNizet您能否提供一个示例作为答案,因为我不能更改类这一事实让人困惑,如果您需要,我会提供更多信息。唯一的问题是internalContent在jar中,没有“accept”方法,我设法解决了它,就像:公共类SomeTextContent扩展InternalTextContent实现内容{@Override public void accept(ContentVisitor ContentVisitor){ContentVisitor.visit(this);}您将需要修改共享类,但正如您所看到的,修改很小且通用,与project1或project2中的任何内容都没有任何耦合。否则,您将需要适配器类。这将意味着强制转换?:-)如果你完全没有办法修改共享类,我认为你不需要任何强制转换就不能做你想做的事情。但是你可以把它限制在一个地方,它会返回一个适配器类,你可以按照你想要的方式修改它,从而在上面使用多态性
interface InternalContentVisitor<T> {
T visitText(InternalTextContent c);
T visitImage(InternalImageContent c);
}
public abstract class InternalContent {
public abstract <T> T accept(InternalContentVisitor<T> visitor);
// ...
}
public class InternalTextContent {
@Override
public <T> T accept(InternalContentVisitor<T> visitor) {
return visitor.visitText(this);
}
}
public class InternalImageContent {
@Override
public <T> T accept(InternalContentVisitor<T> visitor) {
return visitor.visitImage(this);
}
}
InternalContent content = ...; // you don't know the actual type
Copier copier = new Copier();
Copy copy = content.accept(new InternalContentVisitor<Copy>() {
@Override
public Copy visitText(InternalTextContent c) {
return copier.copyText(c.getText());
}
@Override
public Copy visitImage(InternalImageContent c) {
return copier.copyImage(c.getImage());
}
});