[英]Having trouble with strategy pattern and writing multiple classes to text file
I have multiple classes whose properties need to be written to a text file. 我有多个需要将其属性写入文本文件的类。 Since each class has different properties each requires a different algorithm to write.
由于每个类具有不同的属性,因此每个类都需要使用不同的算法来编写。 I'm trying to use a strategy pattern for this but it doesn't seem to be working out - don't know if this is even the correct pattern to use?
我正在尝试为此使用策略模式,但似乎无法解决问题-不知道这是否是正确的模式?
class A
{
void one;
void two;
void three;
}
class B
{
void four;
void five;
void six;
void seven;
}
class C
{
void eight;
void nine;
}
This is where im having trouble with my design, how would I pass the object into the concrete strategy? 这是我在设计上遇到麻烦的地方,如何将对象传递给具体策略?
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()
{
}
}
So then I can just simply do something like this: 因此,我可以简单地执行以下操作:
class Test()
{
void testClassA()
{
ClassA classA = new ClassA();
classA.setOne("One");
classA.setTwo("Two");
classA.setThree("Three");
DataParser parser = new DataParser(classA);
parser.writeData();
}
}
Then the ClassA.txt should have the following: "one|two|three" 然后,ClassA.txt应具有以下内容:“一个|两个|三个”
I think the strategy interface might be a little overkill for what you are trying to achieve. 我认为策略界面可能对您要实现的目标有些过大。 An interface will probably get you what you want:
一个接口可能会为您提供所需的东西:
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
}
}
Repeat for ClassB
and ClassC
... 对
ClassB
和ClassC
重复ClassC
...
Here is a long shot , i have seen in your code the following: 这是一个远景,我在您的代码中看到以下内容:
parsers.put(new ClassA(), new ClassAParser());
but i cannot find where you declare this variable (i guess is wrong copy-paste) Anyway, i assume that you use a HashMap because of the method put(). 但我找不到您在何处声明此变量(我猜错了复制粘贴),无论如何,由于方法put(),我认为您使用的是HashMap。 If this is the case you need to implement both equals() and hashCode() in the classes A, B, C. see here why
如果是这种情况,则需要在类A,B,C中同时实现equals()和hashCode()。
Understanding the workings of equals and hashCode in a HashMap 了解HashMap中的equals和hashCode的工作原理
http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html http://www.ibm.com/developerworks/java/library/j-jtp05273/index.html
(in short words if you don't override these methods then the object you pass in the (简而言之,如果您不覆盖这些方法,则您在
parsers.get(this.object);
should be the exact same instance with the one of the objects you have putted in your map but in your case it is not) 应该与您放置在地图中的对象之一完全相同,但是在您的情况下不是)
You could use a generic interface for the parser. 您可以为解析器使用通用接口。
public interface ParserInterface<T> {
void setObject(T object);
void read();
void write();
}
public class ClassAParser implements ParserInterface<ClassA> { ... }
As Pitelk mentioned, the map of object and parser seems wrong. 如Pitelk所述,对象和解析器的映射似乎是错误的。 Instead you'll want to use a map of class to parser:
相反,您将需要使用类映射来解析器:
parsers.add(ClassA.class, new ClassAParser());
// etc.
Besides: creating instances of all parser implementations in the constructor of DataParser
is unnecessary overhead. 此外:在
DataParser
的构造函数中创建所有解析器实现的DataParser
是不必要的开销。 You could create only the needed instance using an if
/ else if
chain and Object.getClass
or instanceof
in the constructor or make the map a static member of your class. 您可以使用
if
/ else if
链和Object.getClass
或instanceof
在构造函数中仅创建所需的实例,或者使映射成为类的静态成员。
writeData
then becomes: 然后
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();
}
The compiler will generate a warning about unchecked casts. 编译器将生成有关未经检查的强制转换的警告。 But if used correctly, ie
parsers.get(c)
returns a compatible parser, it can be ignored or suppressed. 但是,如果使用正确,即
parsers.get(c)
返回兼容的解析器,则可以将其忽略或抑制。
You can use the same mode as described in Java: If-else instanceof extended classes if you don't want to let your class implements an interface. 您可以使用Java中描述的相同模式:如果不想让您的类实现接口,则为扩展类的 if -else instance 。 To factory class you have to pass object to write and where to write.
对于工厂类,您必须传递要写入的对象以及在何处写入。
Another way can be to use a template method pattern in this way: 另一种方法可以是通过这种方式使用模板方法模式:
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();
}
}
then create a writer for all 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");
}
}
I don't see the need for a "strategy", here (at least that sounds too heavy-weight for me in this case). 我认为这里不需要“战略”(至少在这种情况下,这听起来对我来说太沉重了)。 Also, I wouldn't "map" anything explicitly here.
另外,我不会在这里明确“映射”任何内容。
So basically I've understood that you'll have objects of the given classes at some time in your application, and then want to create text files in a format defined freely by yourself. 因此,基本上我已经了解到,您的应用程序中有时会拥有给定类的对象,然后希望以自己自由定义的格式创建文本文件。 This is perfectly valid as a requirement, so I won't point you to any conventions or tools, here.
这是完全有效的要求,因此在这里我不会为您指出任何约定或工具。 However I also understand that you don't want to do the "serialization" individually within each of the classes, but rather use one (custom) "serializer", probably application-wide.
但是,我也了解到,您不想在每个类中单独进行“序列化”,而是使用一个(自定义)“序列化器”,可能在整个应用程序范围内。 This is where my suggestion differs from other answers.
这是我的建议与其他答案不同的地方。
The method which will actually create the text files needs at least these pieces of information: 实际创建文本文件的方法至少需要以下信息:
My personal approch would thus be to implement a Util method being as specific as allowed in your case, and as generic as needed to avoid duplicate code. 因此,我个人的做法是实现一个Util方法,该方法应根据您的情况允许,并且应根据需要采用通用方法,以避免重复代码。
Within that method, I'd iterate (using reflection) over either: 在该方法中,我将迭代(使用反射):
For the latter variant you'll need to implement your own Annotation to mark the desired properties, or just use the existing "@Transient" annotation to sort out the non-wanted ones. 对于后一种变体,您需要实现自己的注释来标记所需的属性,或者仅使用现有的“ @Transient”注释来整理不需要的注释。 Wait, you'll certainly want the annotation to have
RetentionPolicy.RUNTIME
: 等一下,您肯定会希望注释具有
RetentionPolicy.RUNTIME
:
//...
@Retention( RetentionPolicy.RUNTIME )
public @interface MyAnnotation
//...
But maybe you don't even need to explicitly mark or select properties, particularly if your classes are purely value-holding. 但是也许您甚至不需要显式标记或选择属性,尤其是在您的类纯粹是价值持有的情况下。
Once you've accessed a given property within the suggested loop, simply make use of String.valueOf (ex- or implicitly) to send the "contents" of that property to a writer, or append to a file directly. 在建议的循环中访问了给定的属性后,只需使用String.valueOf(外部或隐式)将该属性的“内容”发送给编写者,或直接附加到文件。
Java serialization generally aims to descend further in object "trees", since any of your properties may be a complex object of its own, requiring more or less sophisticated serialization again. Java序列化通常旨在进一步深入对象“树”,因为您的任何属性都可能是其自身的复杂对象,因此或多或少需要复杂的序列化。
But I've understood that you rather need a simple, "flat" solution here. 但是我了解到,您这里需要一个简单的“扁平”解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.