Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/350.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 在策略模式和将多个类写入文本文件方面遇到问题_Java_Design Patterns - Fatal编程技术网

Java 在策略模式和将多个类写入文本文件方面遇到问题

Java 在策略模式和将多个类写入文本文件方面遇到问题,java,design-patterns,Java,Design Patterns,我有多个类,它们的属性需要写入文本文件。因为每个类都有不同的属性,所以每个类都需要不同的算法来编写。我正在尝试使用一种策略模式来解决这个问题,但它似乎不起作用-不知道这是否是正确的模式 class A { void one; void two; void three; } class B { void four; void five; void six; void seven; } class C { void eight;

我有多个类,它们的属性需要写入文本文件。因为每个类都有不同的属性,所以每个类都需要不同的算法来编写。我正在尝试使用一种策略模式来解决这个问题,但它似乎不起作用-不知道这是否是正确的模式

class A 
{
    void one;
    void two;
    void three;
}

class B
{
    void four;
    void five;
    void six;
    void seven;
}

class C
{
    void eight;
    void nine;
}
这就是我在设计上遇到的问题,我如何将目标传递到具体的策略中

class DataParser
{
    Object object;

    void DataParser(Object object)
    {
        this.object = object;

        parsers.put(new ClassA(), new ClassAParser());
        parsers.put(new ClassB(), new ClassBParser());
        parsers.put(new ClassC(), new ClassCParser());
    }

    void writeData()
    {
        ParserInterface parser = parsers.get(this.object);
        /*
         * classAParser.setClassA(object);
         * classBParser.setClassB(object);
         * classCParser.setClassC(object):
        */
        parser.write();
    }
}

那么我就可以简单地做这样的事情:

class Test()
{
    void testClassA()
    {
        ClassA classA = new ClassA();
        classA.setOne("One");
        classA.setTwo("Two");
        classA.setThree("Three");

        DataParser parser = new DataParser(classA);
        parser.writeData();
    }
}

然后ClassA.txt应该有以下内容:“一|二|三”

我认为策略界面对于您试图实现的目标来说可能有点过分了。界面可能会满足您的需求:

public interface Writable {
  void writeTo(PrintWriter writer);
}

class A implements Writable {
  String one;
  String two;
  String three;

  public void writeTo(PrintWriter writer) {
    // do the writing here
  }
}

ClassB
ClassC
重复上述步骤。

我认为策略界面对于您试图实现的目标来说可能有点过火。界面可能会满足您的需求:

public interface Writable {
  void writeTo(PrintWriter writer);
}

class A implements Writable {
  String one;
  String two;
  String three;

  public void writeTo(PrintWriter writer) {
    // do the writing here
  }
}
ClassB
ClassC
重复上述步骤。…

这是一个很长的过程, 我在您的代码中看到了以下内容:

  parsers.put(new ClassA(), new ClassAParser());
但是我找不到您在哪里声明这个变量(我猜复制粘贴是错误的) 无论如何,我假设您使用HashMap是因为方法put()。 如果是这种情况,则需要在类A、B、C中同时实现equals()和hashCode()。 看这里为什么

(简而言之,如果不重写这些方法,则在

       parsers.get(this.object);
应该与您在地图中放置的一个对象的实例完全相同,但在您的情况下,它不是)

这是一个很长的机会, 我在您的代码中看到了以下内容:

  parsers.put(new ClassA(), new ClassAParser());
但是我找不到您在哪里声明这个变量(我猜复制粘贴是错误的) 无论如何,我假设您使用HashMap是因为方法put()。 如果是这种情况,则需要在类A、B、C中同时实现equals()和hashCode()。 看这里为什么

(简而言之,如果不重写这些方法,则在

       parsers.get(this.object);

应该与放置在映射中的某个对象的实例完全相同,但在您的情况下不是)

您可以为解析器使用通用接口

public interface ParserInterface<T> {
    void setObject(T object);
    void read();
    void write();
}

public class ClassAParser implements ParserInterface<ClassA> { ... }
此外:在
DataParser
的构造函数中创建所有解析器实现的实例是不必要的开销。您可以仅使用构造函数中的
if
/
else if
链和
对象.getClass
instanceof
创建所需的实例,或使映射成为类的静态成员

writeData
然后变为:

void <T> writeData()
{
    ParserInterface<T> parser = (ParserInterface<T>) parsers.get(this.object.getClass());
    parser.setObject((T) this.object);  // <-- same method for all of supported types
    parser.write();
}
void writeData()
{
ParserInterface parser=(ParserInterface)parsers.get(this.object.getClass());

setObject((T)this.object);//您可以为解析器使用通用接口

public interface ParserInterface<T> {
    void setObject(T object);
    void read();
    void write();
}

public class ClassAParser implements ParserInterface<ClassA> { ... }
此外:在
DataParser
的构造函数中创建所有解析器实现的实例是不必要的开销。您可以使用
if
/
else if
链和
对象在构造函数中创建所需的实例。getClass
instanceof
,或者将映射作为cl的静态成员屁股

writeData
然后变为:

void <T> writeData()
{
    ParserInterface<T> parser = (ParserInterface<T>) parsers.get(this.object.getClass());
    parser.setObject((T) this.object);  // <-- same method for all of supported types
    parser.write();
}
void writeData()
{
ParserInterface parser=(ParserInterface)parsers.get(this.object.getClass());

parser.setObject((T)this.object);//如果不想让类实现接口,可以使用中描述的相同模式。对于工厂类,必须传递要写入的对象和写入的位置。
另一种方法是以这种方式使用模板方法模式:

abstract class ParserReaderWriter implements ParserInterface {
  protected abstract String[] getDataToWrite();
  protected abstract PrintWriter createWriter();
  void write() {
    Writer writer = createWriter();

    writer.println(StringUtils.join(getDataToWrite(),"|");
    writer.close();
  }
}
然后为所有writer创建一个writer

class AParserReaderWriter extends ParserReaderWriter {
  ClassA object;
  AParserReaderWriter(ClassA object) {
    this.object = object;
  }
  protected String[] getDataToWrite() {
    return new String[]{this.object.getOne(),...};
  }
  protected PrintWriter createWriter() {
    return new PrintWriter("a.txt");
  }
}

如果不想让类实现接口,可以使用中所述的相同模式。对于factory类,必须传递要写入的对象和要写入的位置。
另一种方法是以这种方式使用模板方法模式:

abstract class ParserReaderWriter implements ParserInterface {
  protected abstract String[] getDataToWrite();
  protected abstract PrintWriter createWriter();
  void write() {
    Writer writer = createWriter();

    writer.println(StringUtils.join(getDataToWrite(),"|");
    writer.close();
  }
}
然后为所有writer创建一个writer

class AParserReaderWriter extends ParserReaderWriter {
  ClassA object;
  AParserReaderWriter(ClassA object) {
    this.object = object;
  }
  protected String[] getDataToWrite() {
    return new String[]{this.object.getOne(),...};
  }
  protected PrintWriter createWriter() {
    return new PrintWriter("a.txt");
  }
}

在这里,我不认为有必要制定“战略”(至少在这种情况下,这听起来对我来说太重了)。此外,我不会在这里明确地“映射”任何东西

所以基本上我知道你会在应用程序中的某个时候拥有给定类的对象,然后想要以自己自由定义的格式创建文本文件。这是一个完全有效的要求,所以我不会在这里向你指出任何约定或工具。但是我也明白你不想这样做在每个类中单独使用“序列化”,但使用一个(自定义)“序列化程序”,可能是应用程序范围内的。这就是我的建议与其他答案的不同之处

实际创建文本文件的方法至少需要以下信息:

  • 实际包含属性值的对象
  • 有哪些属性(甚至:哪些属性实际上需要考虑)
  • 要写入的文件的(基本)名称,以及要使用的字符编码,或者更一般地说,写入程序,或者任何适合您在这方面的特定要求的内容
  • 因此,我个人的方法是实现一个Util方法,该方法在您的案例中尽可能具体,并且尽可能通用,以避免重复代码

    在该方法中,我将迭代(使用反射):

    • 所有可访问(甚至所有已声明)字段
    • 所有带注释的字段
    对于后一种变体,您需要实现自己的注释来标记所需的属性,或者只使用现有的“@Transient”注释来排序非所需的属性。等等,您肯定希望注释具有
    RetentionPolicy。运行时

    //...
    @Retention( RetentionPolicy.RUNTIME )
    public @interface MyAnnotation
    //...
    
    但也许您甚至不需要显式地标记或选择属性,特别是如果您的类纯粹是值持有的

    一旦访问了建议循环中的给定属性,只需使用String.valueOf(ex-or)