介绍
我正在开发一个开源项目Treez,在其中以树状视图组织所谓的“原子”。这些Atom有时具有很多属性,并且可以通过树视图中的用户操作或通过Eclipse代码编辑器中的API来修改这些属性。
我的Atom本身的属性由可重复使用的“ AttributeAtoms”表示。那些拥有实际属性值并提供诸如验证之类的其他功能(“ Atom”的其他可能术语可能是“ widget”,“ bean”,“ property”或“ tree node”)。
问题
过去,我为每个Atom属性提供了一个getter / setter对。这是很多额外的工作,并且炸毁了我的Atom类的大小(请参见下面的代码示例)。现在,我正在寻找一种替代解决方案,
减少了创建新原子的工作量(并减少了维护它们的工作量)。
避免使用“冗余的”吸气剂/设定剂样板代码。
我将在下面描述一些选项。您将使用哪个选项?您是否有关于如何改善这些选择的建议?您还知道其他选择吗?
Getter / Setter代码示例
private AttributeAtom<String> myAttribute = new FilePathAttributeAtom("myAttribtue");
public String getMyAttribute() {
return myAttribute.getValue();
}
public void setMyAttribute(String value) {
this.myAtrribute.setValue(value);
}
相关文章
does java have something similar to C# properties?
(no) Properties in Java?
http://blog.netopyr.com/2011/05/19/creating-javafx-properties/
http://www.eclipse.org/forums/index.php/t/781816/
Why use getters and setters?
What is the advantage of having a private attribute with getters and setters?
考虑的选项
A.使用IDE自动生成的获取器/设置器
Eclipse提供了自动生成getter / setter的可能性。
由于getter / setter代码看起来略有不同,因此不适用于我的AttributeAtom。
不要避免多余的“冗余”代码。
如果我决定保留getter / setter,可以尝试为AttributeAtoms创建类似的内容。另请参阅有关JavaFx属性的自动获取/设置创建的文章(不起作用):
http://www.eclipse.org/forums/index.php/t/781816/
B.生成吸气剂/定型剂的注释(龙目岛计划)
龙目岛(Lombok)提供了使用注释自动生成getter和setter的可能性。
都不适合我的AttributeAtoms
我试图在Eclipse中使用Lombok。编辑器中的代码完成有效,但是我收到“未找到方法”警告。我可能需要花费更多的时间来使Lombok处理经典属性。
另请参见Is it safe to use Project Lombok?
如果我决定使用注释来定义getter / setter,则有可能扩展Lombok以使其适用于我的AttributeAtom。
此处已存在扩展Lombok的JavaFx属性的请求:https://groups.google.com/forum/#!searchin/project-lombok/getter$20and$20setter$20for$20properties/project-lombok/Ik6phxDXHVU/zzDkC2MpmvgJ
这是有关如何使用自定义转换扩展Lambok的介绍:
http://notatube.blogspot.de/2010/12/project-lombok-creating-custom.html
C.所有属性的一个通用获取器/设置器
我可以对所有的Atom属性使用单个getter / setter对
Object get(String attributeName)
void set(String attriuteName, Object value)
可以通过传递其他类型参数来提高类型安全性。
但是,我的Atom的代码完成仅会建议单个getter / setter,而用户将看不到哪些属性可用。 (也许可以通过使用Enums而不是String来标识属性来解决。但是需要以某种方式创建这些Enums。另请参见下一个选项。)
D.自定义Eclipse编辑器和代码处理
也许我可以为我的开源项目编写一个额外的Eclipse插件,通过为代码完成建议相应的伪造方法来“允许访问私有属性”。在编译用户源代码之前,假调用如
myAtom.setMyAttribue(newValue);
将被转换为真正存在的通用getter(选项C)的代码:
myAtom.set("myAttribute", newValue);
E.公共属性
如果我公开我的Atom属性,则不需要每个Atom中的getter / setter代码。而是,可重用的AttributeAtoms将提供get / set方法。用法例如看起来像这样
myAtom.myAttribute.get();
myAtom.myAttribute.set(newValue);
代替
myAtom.getMyAttribute();
myAtom.setMyAttribute(newValue);
一些缺点:
用户需要习惯这种“非常规方法”。 Java用户可能期望
setMyAttribute(newValue)
,而C#用户可能期望myAtom.myAttribute = newValue
。可以交换整个AttributeAtom,但我不想允许它:
myAtom.myAttribute = completelyDifferentAttribute
有什么改善策略吗?
有没有办法允许访问属性的方法而又不允许交换属性本身?我需要一个新的访问修饰符,例如
private *publicMethodAccess* AttributeAtom<String> myAttribute;
原子代码示例
这是一个示例Atom类。如果滚动到底部,您将发现getter / setter消耗的许多代码行。这是丑陋的,不是吗?
package org.treez.results.atom.probe;
import java.util.ArrayList;
import java.util.List;
import org.apache.log4j.Logger;
import org.eclipse.swt.graphics.Image;
import org.treez.core.atom.attribute.AttributeRoot;
import org.treez.core.atom.attribute.ModelPath;
import org.treez.core.atom.attribute.ModelPathSelectionType;
import org.treez.core.atom.attribute.Section;
import org.treez.core.atom.attribute.base.AttributeAtom;
import org.treez.core.atom.variablerange.VariableRange;
import org.treez.core.data.column.ColumnType;
import org.treez.data.column.Columns;
import org.treez.data.output.OutputAtom;
import org.treez.data.table.Table;
import org.treez.results.Activator;
/**
* Collects data from a sweep and puts it in a single (probe-) table. That table can easier be used to produce plots
* than the distributed sweep results.
*/
public class SweepProbe extends AbstractProbe {
/**
* Logger for this class
*/
@SuppressWarnings("unused")
private static Logger sysLog = Logger.getLogger(SweepProbe.class);
//#region ATTRIBUTES
private AttributeAtom<String> xLabel;
private ModelPath xRange;
private AttributeAtom<String> yLabel;
private AttributeAtom<String> firstFamilyLabel;
private ModelPath firstFamilyRange;
private AttributeAtom<String> secondFamilyLabel;
private ModelPath secondFamilyRange;
private AttributeAtom<String> probeName;
private ModelPath sweepOutputModel;
private ModelPath firstProbeTable;
private AttributeAtom<String> probeColumnIndex;
private AttributeAtom<String> probeRowIndex;
//#end region
//#region CONSTRUCTORS
/**
* Constructor
*
* @param name
*/
public SweepProbe(String name) {
super(name);
createPropertyModel();
}
//#end region
//#region METHODS
/**
* Creates the model for the property control
*/
private void createPropertyModel() {
//root
AttributeRoot root = new AttributeRoot("root");
//page
org.treez.core.atom.attribute.Page page = root.createPage("page");
//x section
Section xSection = page.createSection("xSection", "X");
xSection.createSectionAction("action", "Run probe", () -> execute(treeViewRefreshable));
xLabel = xSection.createTextField("xLabel", "Label for x-Axis", "x");
xRange = xSection.createModelPath("xRange", "Range for x-Axis", "", VariableRange.class, this);
xRange.setSelectionType(ModelPathSelectionType.FLAT);
xRange.setValue("root.studies.sweep.threshold");
//y section
Section ySection = page.createSection("ySection", "Y");
yLabel = ySection.createTextField("yLabel", "Label for y-Axis", "y");
//first family section
Section firstFamilySection = page.createSection("firstFamily", "First family");
firstFamilySection.setExpanded(false);
firstFamilyLabel = firstFamilySection.createTextField("firstFamilyLabel", "Label for first family", "family1");
firstFamilyRange = firstFamilySection.createModelPath("firstFamilyRange", "Range for first family", "",
VariableRange.class, this);
//second family section
Section secondFamilySection = page.createSection("secondFamily", "Second family");
secondFamilySection.setExpanded(false);
secondFamilyLabel = secondFamilySection.createTextField("secondFamilyLabel", "Label for second family",
"family2");
secondFamilyRange = secondFamilySection.createModelPath("secondFamilyRange", "Range for second family", "",
VariableRange.class, this);
//probe section
Section probeSection = page.createSection("probe", "Probe");
probeName = probeSection.createTextField("propeName", "Name", "MyProbe");
sweepOutputModel = probeSection.createModelPath("sweepOutput", "SweepOutput", "", OutputAtom.class, this);
firstProbeTable = probeSection.createModelPath("tablePath", sweepOutputModel, Table.class);
firstProbeTable.setLabel("First probe table");
probeColumnIndex = probeSection.createTextField("probeColumnIndex", "Column index", "0");
probeRowIndex = probeSection.createTextField("probeColumnIndex", "Row index", "0");
setModel(root);
}
/**
* Provides an image to represent this atom
*/
@Override
public Image provideBaseImage() {
Image baseImage = Activator.getImage("sweep.png");
return baseImage;
}
//#region CREATE TABLE COLUMNS
/**
* Creates the required columns for the given table
*
* @param table
*/
@Override
protected void createTableColumns(Table table) {
//TODO
}
//#end region
//#region COLLECT PROBE DATA
@Override
protected void collectProbeDataAndFillTable() {
// TODO Auto-generated method stub
}
//#end region
//#end region
//#region ACCESSORS
//#region X LABEL
/**
* @return
*/
public String getXLabel() {
return xLabel.getValue();
}
/**
* @param label
*/
public void setXLabel(String label) {
xLabel.setValue(label);
}
//#end region
//#region X RANGE
/**
* @return
*/
public String getXRange() {
return xRange.getValue();
}
/**
* @param range
*/
public void setXRange(String range) {
xRange.setValue(range);
}
//#end region
//#region Y LABEL
/**
* @return
*/
public String getYLabel() {
return yLabel.getValue();
}
/**
* @param label
*/
public void setYLabel(String label) {
yLabel.setValue(label);
}
//#end region
//#region FIRST FAMILY LABEL
/**
* @return
*/
public String getFirstFamilyLabel() {
return firstFamilyLabel.getValue();
}
/**
* @param label
*/
public void setFirstFamilyLabel(String label) {
firstFamilyLabel.setValue(label);
}
//#end region
//#region FIRST FAMILY RANGE
/**
* @return
*/
public String getFirstFamilyRange() {
return firstFamilyRange.getValue();
}
/**
* @param range
*/
public void setFirstFamilyRange(String range) {
firstFamilyRange.setValue(range);
}
//#end region
//#region SECOND FAMILY LABEL
/**
* @return
*/
public String getSecondFamilyLabel() {
return secondFamilyLabel.getValue();
}
/**
* @param label
*/
public void setSecondFamilyLabel(String label) {
secondFamilyLabel.setValue(label);
}
//#end region
//#region SECOND FAMILY RANGE
/**
* @return
*/
public String getSecondFamilyRange() {
return secondFamilyRange.getValue();
}
/**
* @param range
*/
public void setSecondFamilyRange(String range) {
secondFamilyRange.setValue(range);
}
//#end region
//#region PROBE
/**
* @return
*/
public String getProbeName() {
return probeName.getValue();
}
/**
* @param name
*/
public void setProbeName(String name) {
probeName.setValue(name);
}
//#end region
//#region SWEEP OUTPUT MODEL
/**
* @return
*/
public String getSweepOutputModelName() {
return sweepOutputModel.getValue();
}
/**
* @param sweepOutputModel
*/
public void setSweepOutputModelName(String sweepOutputModel) {
this.sweepOutputModel.setValue(sweepOutputModel);
}
//#end region
//#region PROBE TABLE
/**
* @return
*/
public String getFirstProbeTable() {
return firstProbeTable.getValue();
}
/**
* @param firstProbeTable
*/
public void setFirstProbeTable(String firstProbeTable) {
this.firstProbeTable.setValue(firstProbeTable);
}
//#end region
//#region COLUMN INDEX
/**
* @return
*/
public String getProbeColumnIndex() {
return probeColumnIndex.getValue();
}
/**
* @param index
*/
public void setProbeColumnIndex(String index) {
probeColumnIndex.setValue(index);
}
//#end region
//#region ROW INDEX
/**
* @return
*/
public String getProbeRowIndex() {
return probeRowIndex.getValue();
}
/**
* @param index
*/
public void setProbeRowIndex(String index) {
probeRowIndex.setValue(index);
}
//#end region
//#end region
}
最佳答案
对于选项E,通过使用“ final”修饰符,可以防止换入全新的AttributeAtom,同时仍然允许获取/设置:
public final AttributeAtom<String> myAttribute = new FilePathAttributeAtom("myAttribtue");
然后将允许以下内容:
myAtom.myAttribute.get();
myAtom.myAttribute.set(newValue)
但是您担心的事情不会是:
myAtom.myAttribute = completelyDifferentAttribute
关于java - Java中的“特殊属性/属性”而不是getter/setter,以避免样板代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31357420/