Java 序列化复合-(设计模式)的最佳方法
我有以下实现复合设计模式的java代码:Java 序列化复合-(设计模式)的最佳方法,java,serialization,design-patterns,composite,Java,Serialization,Design Patterns,Composite,我有以下实现复合设计模式的java代码: //composite designed for type safety (all Leaf-only operations only in leaf) interface Component extends Visitable { void enable(); void disable(); } class CompositeA implements Component { private String compositeData;
//composite designed for type safety (all Leaf-only operations only in leaf)
interface Component extends Visitable {
void enable();
void disable();
}
class CompositeA implements Component {
private String compositeData;
private boolean enabled;
private Set<Component> components = new HashSet<>();
CompositeA(String compositeData) {
this.compositeData = compositeData;
}
void addChild(Component component){
this.components.add(component);
}
String getCompositeData() {
return compositeData;
}
Set<Component> getComponents() {
return components;
}
@Override
public void enable() {
this.enabled = true;
}
@Override
public void disable() {
this.enabled = false;
}
@Override
public Object accept(ComponentVisitor visitor) {
return visitor.visit(this);
}
}
class CompositeB implements Component{
private int compositeData;
private boolean enabled;
private Set<Component> components = new HashSet<>();
CompositeB(int compositeData) {
this.compositeData = compositeData;
}
void addChild(Component component){
this.components.add(component);
}
int getCompositeData() {
return compositeData;
}
Set<Component> getComponents() {
return components;
}
@Override
public void enable() {
this.enabled = true;
}
@Override
public void disable() {
this.enabled = false;
}
@Override
public Object accept(ComponentVisitor visitor) {
return visitor.visit(this);
}
}
class Leaf implements Component {
private boolean enabled;
private String[] leafData;
Leaf(String[] leafData) {
this.leafData = leafData;
}
String[] getLeafData() {
return leafData;
}
@Override
public void enable() {
this.enabled = true;
}
@Override
public void disable() {
this.enabled = false;
}
@Override
public Object accept(ComponentVisitor visitor) {
return visitor.visit(this);
}
}
现在,如果我使用访问者模式进行序列化,我会得到如下结果:
interface ComponentVisitor {
WholeCompositeASerialized visit(CompositeA compositeA);
WholeCompositeBSerialized visit(CompositeB compositeB);
WholeLeafSerialized visit(Leaf leaf);
}
class SerializableComponentVisitor implements ComponentVisitor{
@Override
public WholeCompositeASerialized visit(CompositeA compositeA) {
WholeCompositeASerialized wcas = new WholeCompositeASerialized();
wcas.serializedChildren = compositeA
.getComponents()
.stream()
.map(c -> c.accept(this))
.collect(Collectors.toList());
wcas.content = compositeA.getCompositeData();
return wcas;
}
@Override
public WholeCompositeBSerialized visit(CompositeB compositeB) {
WholeCompositeBSerialized wcbs = new WholeCompositeBSerialized();
wcbs.serializedChildren = compositeB
.getComponents()
.stream()
.map(c -> c.accept(this))
.collect(Collectors.toList());
wcbs.content = String.valueOf(compositeB.getCompositeData());
return wcbs;
}
@Override
public WholeLeafSerialized visit(Leaf leaf) {
WholeLeafSerialized wls = new WholeLeafSerialized();
wls.content = Arrays.toString(leaf.getLeafData());
return wls;
}
}
interface Visitable{
Object accept(ComponentVisitor visitor);
}
如果我使用instanceof
这就是做同样事情的代码:
class SerializerUsingInstanceOf {
Object decide(Component component){
if(component instanceof CompositeA){
return serialize((CompositeA)component);
}
else if(component instanceof CompositeB){
return serialize((CompositeB)component);
}
else{
return serialize((Leaf)component);
}
}
WholeCompositeASerialized serialize(CompositeA compositeA) {
WholeCompositeASerialized wcas = new WholeCompositeASerialized();
wcas.serializedChildren = compositeA
.getComponents()
.stream()
.map(this::decide)
.collect(Collectors.toList());
wcas.content = compositeA.getCompositeData();
return wcas;
}
WholeCompositeBSerialized serialize(CompositeB compositeB) {
WholeCompositeBSerialized wcbs = new WholeCompositeBSerialized();
wcbs.serializedChildren = compositeB
.getComponents()
.stream()
.map(this::decide)
.collect(Collectors.toList());
wcbs.content = String.valueOf(compositeB.getCompositeData());
return wcbs;
}
WholeLeafSerialized serialize(Leaf leaf) {
WholeLeafSerialized wls = new WholeLeafSerialized();
wls.content = Arrays.toString(leaf.getLeafData());
return wls;
}
}
我猜这里更喜欢visitor,因为当我们添加新的组件时,我们还需要实现对象接受(ComponentVisitor)
方法,所以我们不能忘记我们需要一个用于序列化这个新组件的代码。如果我们在使用instanceof
时也这样做,我们可能会忘记将其添加到该检查中
现在-我的问题是-我们有没有办法摆脱对象accept(ComponentVisitor)
方法签名中丑陋的对象
返回类型?我想到的唯一其他选择是使用一些标记接口(例如,接口序列化组件{}
)然后让所有序列化程序类实现这个空接口,就像这样类wholecompositerialized实现SerializedComponent
,但它似乎仍然不正确。我认为正确的方法可能是在这里使用泛型
e、 g
公共类主{
公共静态void main(字符串[]args){
ComponentVisitor序列化程序=新的ComponentSerializer();
组件A=新组件A();
SerializedComponent serializedA=componentA.accept(序列化程序);
System.out.println(序列化DA);
组件=新组件B();
SerializedComponent serializedB=component.accept(序列化程序);
System.out.println(序列化数据库);
}
静态接口组件{
公共V接受(组件访客);
}
静态类ComponentA实现组件{
公共V接受(组件访问者){
回访者。参观(本);
}
}
静态类ComponentB实现组件{
公共V接受(组件访问者){
回访者。参观(本);
}
}
静态接口序列化组件{}
静态类SerializedComponent实现SerializedComponent{
}
静态类SerializedComponentB实现SerializedComponent{
}
静态接口组件访问者{
公众V访问(组件A组件);
公众V访问(组件B组件);
}
静态类ComponentSerializer实现ComponentVisitor{
公共序列化组件访问(组件A组件){
返回新的SerializedComponentA();
}
公共序列化组件访问(组件B组件){
返回新的SerializedComponentB();
}
}
}
您试图从访问者返回具体类型信息。这不是该模式的目的。访问者在内部封装(并处理)具体类型
这里的解决方案是将所有特定于ComponentA
(或您可能将其转换为的任何特定于A的类型)的逻辑移动到visit(ComponentA)
方法中,同样地,对于ComponentB
如果您不希望访问者的类型封装,那么更适合使用不同的设计,例如模式匹配
对评论的评论
public static void main(String[] args) {
// Using a concrete type here defeats the purpose of these patterns.
// Instead, program to an interface:
// Component c1 = new CompositeA("root");
CompositeA c1 = new CompositeA("root");
c1.addChild(new Leaf(new String[]{"leaf11", "leaf12"}));
CompositeA c2 = new CompositeA("composite1");
c2.addChild(new Leaf(new String[]{"leaf21", "leaf22"}));
c1.addChild(c2);
SerializableComponentVisitor scv = new SerializableComponentVisitor();
// Clients never invoke visit methods directly,
// because they do not have the type information to make these calls.
// A client would execute, c1.accept(scv)
WholeCompositeASerialized wcas1 = scv.visit(c1);
}
我在这里看到的问题是,visit必须返回相同的SerializedComponent
对象。当我想将组件a
序列化为序列化组件a
和组件b
序列化为序列化组件b
时会发生什么情况?这很好,因为Composite实现了V accept()
而不是Object accept()
,但我仍然需要创建ComponentVisitor
?因此肯定比在Composite中包含Object
要好,但是有可能完全摆脱对象
/Marker接口吗?@MarkoKraljevic不知道你第一句话的意思。示例代码已返回SerializedA和SerializedDB。它返回SerializedComponent
。因此,如果我想将它转发到方法printSerializedComponent(SerializedComponent a)
@MarkoKraljevic,我需要手动强制转换该类型。您必须返回一个基类型,否则调用方必须事先知道它处理的对象的类型。您仍然可以使用SerializedComponentVisitor
打印这些内容,而不是强制转换。序列化组件的模式相同。以这种方式使用时有什么问题?对我来说,这似乎是一个不错的解决方案->我只是将SerializationMarkerInterface返回类型重写为将由代码生成的具体序列化类型。Visitor是一种为本机不支持它的语言实现模式匹配的方法。@plalx模式匹配将在下一个Java版本中出现,但它仍然会在instanceof
和隐式cast下面使用-我在某个地方读到,根据Liskov替换原理,使用它是不好的。。。现在我不知道缺点是什么,但请记住阅读…@jaco0646你能在线修改我的示例吗gdb.com/H1gxCWsEwv,因为我不明白你的意思吗?@plalx,是的:模式匹配是一种功能设计模式,访问者可以被描述为从OO到FP的桥梁。虽然封装对OO设计至关重要,但FP对此却更加矛盾。我可以说,“如果你不想封装OO,那么一个不同的范例可能更合适,比如FP。”我认为这些模式代表了它们各自的范例。
public class Main {
public static void main(String []args){
ComponentVisitor<SerializedComponent> serializer = new ComponentSerializer();
Component componentA = new ComponentA();
SerializedComponent serializedA = componentA.accept(serializer);
System.out.println(serializedA);
Component component = new ComponentB();
SerializedComponent serializedB = component.accept(serializer);
System.out.println(serializedB);
}
static interface Component {
public <V> V accept(ComponentVisitor<V> visitor);
}
static class ComponentA implements Component {
public <V> V accept(ComponentVisitor<V> visitor) {
return visitor.visit(this);
}
}
static class ComponentB implements Component {
public <V> V accept(ComponentVisitor<V> visitor) {
return visitor.visit(this);
}
}
static interface SerializedComponent {}
static class SerializedComponentA implements SerializedComponent {
}
static class SerializedComponentB implements SerializedComponent {
}
static interface ComponentVisitor<V> {
public V visit(ComponentA component);
public V visit(ComponentB component);
}
static class ComponentSerializer implements ComponentVisitor<SerializedComponent> {
public SerializedComponent visit(ComponentA component) {
return new SerializedComponentA();
}
public SerializedComponent visit(ComponentB component) {
return new SerializedComponentB();
}
}
}
public static void main(String[] args) {
// Using a concrete type here defeats the purpose of these patterns.
// Instead, program to an interface:
// Component c1 = new CompositeA("root");
CompositeA c1 = new CompositeA("root");
c1.addChild(new Leaf(new String[]{"leaf11", "leaf12"}));
CompositeA c2 = new CompositeA("composite1");
c2.addChild(new Leaf(new String[]{"leaf21", "leaf22"}));
c1.addChild(c2);
SerializableComponentVisitor scv = new SerializableComponentVisitor();
// Clients never invoke visit methods directly,
// because they do not have the type information to make these calls.
// A client would execute, c1.accept(scv)
WholeCompositeASerialized wcas1 = scv.visit(c1);
}