忘记你在 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();
}
}
只需直接访问成员并为自己节省数百行代码(就像您建议的那样)。
这导致了这个问题的第二个答案..
二:
设计坦克..
您的代码可能正在腐烂。拉姆齐厨师会感到羞愧。原因如下:
显然,上面OtherClass
的内容完全没用,因为它的功能可以(并且应该)放在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 [g t l p cg d b 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}))
上面的这个例子是一个系统,它从两个答案中获取点并将它们组合成一个隐藏不需要的成员,结合逻辑功能(获取“内容”的功能),并使用不需要大量闪亮样板的语言代码..
替换类/对象系统
虽然这是一个很好的例子,说明了如何用函数式语言对对象进行建模,但对于 Clojure 和一般的函数式编程来说,它并不完全符合习惯。对于更简单的处理结构化数据的方法,请查看 Clojure StructMaps和Records。
2017 更新
只需使用Kotlin 即可。它正在全面治愈 Java 病。它对所有这些东西都有一流的语言支持,编译器甚至会帮助你摆脱无用的样板。它已经存在了 7 年多,并且自 2016 年 2 月以来一直在稳定发布。如果我一开始就知道它,我可能不会包括 Closure。