如何避免具有许多实例变量的类中的getter / setter

我会尽量保持简短。

我有许多实例变量(30+)的类,因此有很多getter / setter。 这些类本身很简单,但是由于getter / setter,LOC刚刚爆炸(并且还有太多的代码欺骗性)。

所以我删除了属性并将它们存储在地图中,就像这样

public class MyTechnicalToolClassX { //...constructor private Map data; public Object getAttributeByKey(AttributeKey key) { // ...doStuff, check data associated with key, etc // if (predicate == true) return otherData; return data.get(key.toString()); } public void setAttributeByKey(AttributeKey key, Object value) throws IllegalArgumentException { if(key.getType().isInstance(value)) { data.put(key.toString(), value); } else { throw IllegalArgumentException("The passed value has the wrong type, we expect: " + key.getType().getName()); } } public enum AttributeKey { someKey1("key1", String.class), someKey2("key2", Date.class), //... someKeyN("keyN", SomeType.class); private String key; private Class valueType; AttributeKey(String key, Class valueType) { this.key = key; this.valueType = valueType; } @Override public String toString() { return key; } public Class getType() { return valueType; } } // AttributeKey } // MyTechnicalToolClassX 

AttributeKey曾经只是一个字符串,但这样我就可以确保setter中的类型安全。 现在我的问题是,我删除了类中的代码重复性,但我有其他类也有很多属性(因为它们代表了一些技术对象……),这里最好的方法是什么? 为每个类提供自己的AttributeKey枚举?

我补充了一些想法。 我现在在编译时有类型安全性。 这是我的getter和setter的新界面。

 public  void setAttributeByName(IAttribute attribute, SetVal value); public  Type getAttributeByName(IAttribute attribute); 

约书亚布洛赫称这种概念类型安全的异构容器 。

忘记你在OOP学校学到的东西!

我们已经有3年了。 我们现在有更好的语言。 Swift,Rust,Kotlin,Go等。我们理解数据/值类型与操作它的代码之间的区别。 适当的企业CLEAN架构在Java领域提倡这一点。 但Java只是不为这种模式提供语言级支持。 最终结果是大量使用(仍然是很棒的)RxJava,以及进行代码生成等的注释处理器。但是现在很难快乐地拖拽Java的遗产。 Kotlin倾向于以一种Java无法以非常低的价格解决Java问题:缺乏严格的源兼容性(它不是Groovy)。

原始答案,底部更新。

有两个答案。

一:

无用的锅炉!

如果类表示一些大型数据对象,则听起来大多数成员变量只是数据的容器。 在这种情况下,严格遵循OOP信息隐藏惯例并不重要。 人们经常混淆这个公约的目的,最终滥用它。 它只是为了防止程序员不得不处理对象的复杂和不必要的内部工作。 而不是掩盖整个对象,只是掩盖不应该被搞乱的部分。 在您只是从数据库映射信息或充当存储容器的情况下,代码如下:

 import java.util.Date; public class Article { protected int id; protected String guid; protected String title; protected String link; protected Date pubDate; protected String category; protected String description; protected String body; protected String comments; protected Article (String articleTitle, String articleBody) { title = articleTitle; body = articleBody; } protected Article (String guid, String articleTitle, String articleLink, long publicationDate, String category, String description, String articleBody, String commentsLink) { this(articleTitle, articleBody); this.guid = guid; this.link = articleLink; this.pubDate = new Date(publicationDate); this.category = category; this.description = description; this.comments = commentsLink; } protected Article (int id, String guid, String articleTitle, String articleLink, long publicationDate, String category, String description, String articleBody, String commentsLink) { this(guid, articleTitle, articleLink, publicationDate, category, description, articleBody, commentsLink); this.id = id; } protected int getId() { return id; } protected String getTitle() { return title; } protected String getGuid() { return guid; } protected String getLink() { return link; } protected String getComments() { return comments; } protected String getCategory() { return category; } protected String getDescription() { return description; } protected String getBody() { return body; } protected void setId(int id) { this.id = id; } protected void setGuid(String guid) { this.guid = guid; } protected void setTitle(String title) { this.title = title; } protected void setLink(String link) { this.link = link; } protected void setPubDate(Date pubDate) { this.pubDate = pubDate; } protected void setCategory(String category) { this.category = category; } protected void setDescription(String description) { this.description = description; } protected void setBody(String body) { this.body = body; } protected void setComments(String comments) { this.comments = comments; } } 

..完全可恶。

在这种情况下,没有理由仅仅为了访问数据对象的成员而完成所有额外的工作。 特别是如果您只是在几个外部代码行中使用它们:

 public OtherClass { private Article article; public OtherClass(Article data) { article = data; } public String getArticleContents() { return (new StringBuilder()) .append(article.getTitle()) .append(article.getCategory()) .append(dateToString(article.getPubDate()) .append(article.getBody()) .toString(); } } 

只需直接访问成员并节省数百行代码(就像你建议你尝试做的那样)。

这导致了这个问题的第二个答案。

二:

设计Stank ..

你的代码可能会腐烂。 厨师拉姆齐会感到羞耻。 原因如下:

显然,上面的OtherClass完全没用,因为它的function可以(并且应该)放在Article类中,而不是包含在其他一些无用的,不需要的,文件系统乱丢垃圾的OtherClass 。 如果你这样做,你甚至可以忘记需要getter和setter 以及 OtherClass因为与它连接的东西可能只需要文章内容而不是标题,正文等。 在这种方法中, Article类隐藏了来自外部世界的所有内容,并且仅提供绝对需要的信息。

由于这些是您问题的两个完全可行的答案,因此必须有一个解决方案。

使用Clojure

建模对象

虽然您可以使用闭包来建模对象 ,但是有更好的方法。 有趣的是,在一种将函数视为一等公民的语言中,您可以完全使用地图来模拟传统的面向对象范例 – 当您开始在重构30多个成员字段类系统时,您会发现被给予。

将其与原始Article + OtherClass方法进行比较:

 (defn Article [] (let [id (atom nil) guid (atom nil) title (atom nil) link (atom nil) pubdate (atom nil) category (atom nil) description (atom nil) body (atom nil) comments (atom nil) set (fn [gtlp cg db cm] (do (reset! guid g) (reset! title t) (reset! link l) (reset! pubdate p) (reset! category cg) (reset! description d) (reset! body b) (reset! commments cm))) get (fn [] [@guid @link @description @comments :content (content)]) content #(str title category pubdate body)] {:get get, :set set})) 

以上考试是一个系统,它从两个答案中获取分数并将它们组合成一个隐藏不需要的成员,合并逻辑function(获取’内容’的function),并使用不需要大量shiny样板的语言的系统码..

替换类/对象系统

虽然这是如何使用函数式语言对对象进行建模的一个很好的例子,但对于Clojure和函数式编程来说,它并不完全是惯用的。 要获得更简单的结构化数据方法,请查看Clojure StructMaps和Records 。

2017年更新

只需使用Kotlin 。 它正在全面治愈Java疾病。 它为所有这些东西提供了一流的语言支持,编译器甚至可以帮助你摆脱无用的样板。 自2016年2月以来,它已经存在超过7年并且处于稳定版本。如果我最初了解它,我可能不会包括Closure。

也许您正在寻找像Lambok这样的东西 。

    Interesting Posts