在策略模式上遇到问题并将多个类写入文本文件

时间:2013-09-20 08:55:55

标签: 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;
    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();
    }
}

interface ParserInterface
{
    void write();
    void read();
}

class ClassAParser()
{
    ClassA classA;

    void setClassA(ClassA classA)
    {
        this.classA = classA;
    }

    void write()
    {
        PrinterWriter writer = new PrintWriter("ClassA.txt");

        writer.printLn(this.classA.getOne() + "|" + this.classA.getTwo() + "|" + this.classA.getThree());

        writer.close();
    }

    void read()
    {
    }
}

class ClassBParser()
{
    ClassB classB;

    void setClassB (ClassB classB )
    {
        this.classB = classB ;
    }

    void write()
    {
        PrinterWriter writer = new PrintWriter("ClassB.txt");

        writer.printLn(this.classB.getFour() + "|" + this.classB.getFive() + "|" + this.classB.getSix() + "|" + this.classB.getSeven());

        writer.close();
    }

    void read()
    {
    }
}

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

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应该具有以下内容:“one | two | 3”

5 个答案:

答案 0 :(得分:1)

我认为战略界面可能对你想要实现的目标有点过分。界面可能会得到你想要的东西:

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
  }
}

重复ClassBClassC ...

答案 1 :(得分:1)

这是一个远景, 我在你的代码中看到了以下内容:

  parsers.put(new ClassA(), new ClassAParser());

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

Understanding the workings of equals and hashCode in a HashMap

http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html

(简而言之,如果你不覆盖这些方法,那么你在

中传递的对象
       parsers.get(this.object);

应该是与您在地图中放置的对象之一完全相同的实例,但在您的情况下则不是这样的实例

答案 2 :(得分:1)

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

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

public class ClassAParser implements ParserInterface<ClassA> { ... }

正如Pitelk所说,对象和解析器的地图似乎是错误的。相反,你会想要使用类的映射来解析器:

parsers.add(ClassA.class, new ClassAParser());
// etc.

此外:在DataParser的构造函数中创建所有解析器实现的实例是不必要的开销。您只能在构造函数中使用if / else if链和Object.getClassinstanceof创建所需的实例,或者使地图成为您的类的静态成员。

然后

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();
}

编译器将生成有关未经检查的强制转换的警告。但如果使用正确,即parsers.get(c)返回兼容的解析器,则可以忽略或抑制它。

答案 3 :(得分:1)

如果您不想让您的类实现接口,则可以使用Java: If-else instanceof extended classes中所述的相同模式。对于工厂类,您必须将对象传递给写入和写入的位置 另一种方法是以这种方式使用模板方法模式:

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();
  }
}

然后为所有作家

创建一个作家
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");
  }
}

答案 4 :(得分:1)

我不认为这里需要一个“策略”(至少在这种情况下,这对我来说太重了)。此外,我不会在这里明确地“映射”任何内容。

所以基本上我已经知道你的应用程序中某些时候你会有给定类的对象,然后想要以你自己定义的格式创建文本文件。这完全有效,因此我不会在此指出任何约定或工具。但是我也明白你不想在每个类中单独进行“序列化”,而是使用一个(自定义)“序列化器”,可能是应用程序范围内的。这是我的建议与其他答案不同的地方。

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

  1. 实际包含属性值的对象
  2. 有什么属性(甚至:实际上要考虑哪些属性)
  3. 要写入的文件的(基本)名称 - 以及要使用的字符编码,或者更常见的是Writer,或者符合您在此方面的特定要求的任何内容。
  4. 因此,我个人的approch将实现一个与您的案例中允许的具体相同的Util方法,并根据需要实现通用,以避免重复代码。

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

    • 所有可访问(甚至所有声明的)字段
    • 所有带注释的字段

    对于后一个变体,您需要实现自己的Annotation来标记所需的属性,或者只使用现有的“@Transient”注释来挑选出不需要的属性。等等,你肯定希望注释有RetentionPolicy.RUNTIME

    //...
    @Retention( RetentionPolicy.RUNTIME )
    public @interface MyAnnotation
    //...
    

    但也许你甚至不需要明确标记或选择属性,特别是如果你的类纯粹是持有价值的话。

    在建议的循环中访问给定属性后,只需使用String.valueOf(ex-或者隐式)将该属性的“内容”发送给编写器,或直接附加到文件。 / p>

    Java序列化通常旨在进一步降低对象“树”,因为任何属性都可能是它自己的复杂对象,需要或多或少复杂的序列化。

    但我明白你在这里需要一个简单的“扁平”解决方案。