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)