显示吸气剂
Getters for Display
我正在研究 getters/setters
,一般的想法是它们是邪恶的,应该避免。您应该让对象完成工作并产生结果。
阅读Material:
Why getter and setter methods are evil
Are getters and setters poor design? Contradictory advice seen
Why use getters and setters?
考虑到所有这些,假设我有一本书 class
看起来像这样:
publc final Book{
private final String title;
private final List<Authors> listofAuthors;
private final int numberofpages;
//constructor not included in example.
//getters for title, listofAuthors, and numberofpages
public int numberofpagesleft(int pagesRead){
//code to determine number of pages left
}
public boolean isWrittenBy(Author author){
//code to determine if book contains author
}
}
如果我有一个 UI
(例如 JavaFX
、webpage
等..)并且希望我的 class 是灵活的,会包括 getters
for title
, listofAuthors
and numberofpages
for display purposes break encapsulation
?
示例:
//library is an List<Book> collection, and author is an object of the Author class.
for (Book book : library){
if(book.isWrittenBy(author){
System.out.println("Books in your collection written by " + author.toString() + " include:" );
System.out.println(book.getTitle());
}
}
或
for (Book book : library){
//returns a Collections.unmodifiableList().
if(book.getAuthors(){
//code to build a set of authors in my library
}
}
问题:
正在循环中断中调用getTitle()
或getAuthors()
encapsulation
?
如果以上问题的答案是肯定的,那么我将如何展示这本书 if isWrittenBy()
returns
true
?以及我如何收集图书馆中的所有作者?
有一种学派声称大量的 get/set 方法显示了粗心的面向对象设计。您询问如果您的 Book
对象没有适当的 getXXX
方法,您将如何显示您的 "book" 数据。答案大概是让您的书自行显示:
MyUserInterface interface=...;
...
book.renderToUserInterface (interface);
我认为再次过度使用 get/set 方法的论点有一定的说服力——我认为好的设计可以使程序化 类 成为它们所代表的现实世界事物的良好模型,而现实世界中的事物通常不仅仅是可以设置和查询的离散数据项的存储库。我认为我们确实倾向于认为 类(在 Java 和其他语言中)不过是经过精心设计的数据结构,而且它们可能不止于此。
但是,在我看来,get/set 方法是 "evil" 的想法太过分了。教条地避免这些方法不太可能有帮助,特别是当大多数 OO 程序中发生的很多事情实际上是在支持模型域对象的 类 周围的基础结构时。此外,在考虑应用程序的完整 OO 模型时,"making the object do the work" 最有意义。在 个人 对象的设计层面,例如用于通用库,我认为我们必须有点务实。
我似乎记得 "make the object do the work" 是大约十年前的一个热门想法,但我认为这不再是一件大事了。
object 的属性与 object 的实现细节之间存在差异。
- 一本书有一个标题 - 这不是实现细节。
- 一本书有作者 - 这不是实现细节。
- 一本书的作者是如何存储的 - 这可以是一个实现细节。
Getter 并不邪恶,但您必须小心使用它们,因为它们可以公开限制对您的实现进行更改的实现细节。
class Book {
private ArrayList<Author> authors = new ArrayList<>();
public ArrayList<Author> getAuthors() { return authors; }
}
以上内容很糟糕,原因有二。首先,它 return 是对调用者可修改的 collection,允许调用者更改 collection。其次,它向调用者承诺 returned collection 是一个 ArrayList
.
Book book = ...;
ArrayList<Author> authors = book.getAuthors();
我们通过包装 collection:
解决了第一个问题
class Book {
private ArrayList<Author> authors = new ArrayList<>();
public List<Author> getAuthors() {
return Collection.unmodifiableList(authors);
}
}
Book book = ...;
List<Author> authors = book.getAuthors();
现在调用者不能修改 collection,但他们仍然承诺 collection 是 List
。如果我们发现我们想要将我们的作者存储为 Set
(因为作者不会多次创作一本书),我们不能简单地更改内部存储。
class Book {
private HashSet<Author> authors = new HashSet<>();
public List<Author> getAuthors() {
return Collection.unmodifiableList(authors); // ERROR - authors not a list
}
}
我们必须将作者收集到一个新的 List
中,或者更改 getAuthors()
的签名,但这会影响希望 List
成为 returned.
相反,代码应该只是 return 一个 Collection
。这不会公开 authors
.
存储的实现细节
class Book {
public Collection<Author> getAuthors() {
return Collection.unmodifiableCollection(authors);
}
}
注意:可能是按作者顺序排列的,第一作者排在最前面。在这种情况下,您可能希望 return a List
向调用者保证数据实际上是有序的。在这种情况下,List
不是实现细节,而是接口契约的一部分。
那么,getTitle()
会破坏封装吗?不,绝对不是。
getAuthors()
会破坏封装吗?取决于它 return 的内容,以及您的承诺。如果它 return 是 Collection
,那么不会。如果它 return 是 List
并且您不承诺订购结果,那么可以。
这只是对一些不同但相关(有时是高级)主题的辅助评论,并不是对问题的直接回答(其他答案中已经很好地回答了)。也许这里的信息与这里或您的问题无关,如果是这样,请忽略它:-)
关于不可变性,即不添加二传手
Getter 通常很好,因为调用者无法更改对象,但不必要的 setter 会使推理对象变得更加困难,尤其是在编写并发代码时。
当你有 setter 时,对象的变化源可以来自更广泛的区域,另一个 class 甚至另一个线程。
参见 Immutable Objects in the Java tutorials and a synchronized sample with setters which is just plain more complicated and potentially error prone vs an immutable version without setters。
JavaFX Color class 是 JDK.
中不可变 class 的一个例子
一般来说,当我创建一个 class 时,我通常会尝试将所有输入都放入构造函数参数中,使 class 最终化,而不是添加设置器并使 class决赛。你不能总是那样做,但当你可以时,它似乎让编程对我来说更容易。
请注意,setter 通常是有用和必要的,所以如果需要它们,请不要担心添加它们,不变性只是有时需要的属性,而不是规则。
关于桥接数据模型和显示
如果您真的对从要显示的对象获取数据的不同模式和约定感兴趣,请阅读 Martin Fowler 的 GUI Architectures,因为它对此提供了很好的概述。
通常,您想要 separation of concerns from the data and domain objects and the UI. For small apps, you don't need that separation and it is just more overhead. But, as soon as you start developing larger apps, it usually becomes a lot better organized if you separate the UI from the domain model completely. Usually, observables help to do this, often coupled with a design pattern like MVC, MVP or MVVM。
关于 JavaFX 属性和绑定到显示器
如果使用 JavaFX,正如您在问题中提到的,properties and binding provide an observable interface so a change in your domain object can be reflected automatically in your UI. You can define the properties directly in your data and domain classes. You can define your UI using something like FXML and an FXML Controller. In the controller you can bind properties of the UI (e.g. the text string of a Label) 到数据和域对象中的属性。这样,如果您在内部更改域中 属性 的值,例如图书馆中的书籍数量,您可以将该数字公开为 属性 每当添加新书时它会在 UI 中自动更新(无需明确告诉 UI添加图书时更新标签)。
例如在您的 LibraryController 中,您可能有:
@FXML
Label numberOfBooksInLibraryLabel;
Library library = new Library();
...
numberOfBooksInLibraryLabel.textProperty().bind(
library.books().sizeProperty().asString()
);
关于 JavaFX 属性和封装
JavaFX 有一些关于 JavaFX 属性的约定,这些约定比没有 JavaFX 的普通 Java 更复杂和微妙。为了帮助封装和 JavaFX 属性,请考虑使用 FXCollections.unmodifiableObservableList()
and read only properties。
private final ReadOnlyDoubleWrapper size = new ReadOnlyDoubleWrapper();
public final double getSize() {
return size.get();
}
public final ReadOnlyDoubleProperty sizeProperty() {
return size.getReadOnlyProperty();
}
我正在研究 getters/setters
,一般的想法是它们是邪恶的,应该避免。您应该让对象完成工作并产生结果。
阅读Material:
Why getter and setter methods are evil
Are getters and setters poor design? Contradictory advice seen
Why use getters and setters?
考虑到所有这些,假设我有一本书 class
看起来像这样:
publc final Book{
private final String title;
private final List<Authors> listofAuthors;
private final int numberofpages;
//constructor not included in example.
//getters for title, listofAuthors, and numberofpages
public int numberofpagesleft(int pagesRead){
//code to determine number of pages left
}
public boolean isWrittenBy(Author author){
//code to determine if book contains author
}
}
如果我有一个 UI
(例如 JavaFX
、webpage
等..)并且希望我的 class 是灵活的,会包括 getters
for title
, listofAuthors
and numberofpages
for display purposes break encapsulation
?
示例:
//library is an List<Book> collection, and author is an object of the Author class.
for (Book book : library){
if(book.isWrittenBy(author){
System.out.println("Books in your collection written by " + author.toString() + " include:" );
System.out.println(book.getTitle());
}
}
或
for (Book book : library){
//returns a Collections.unmodifiableList().
if(book.getAuthors(){
//code to build a set of authors in my library
}
}
问题:
正在循环中断中调用
getTitle()
或getAuthors()
encapsulation
?如果以上问题的答案是肯定的,那么我将如何展示这本书 if
isWrittenBy()
returnstrue
?以及我如何收集图书馆中的所有作者?
有一种学派声称大量的 get/set 方法显示了粗心的面向对象设计。您询问如果您的 Book
对象没有适当的 getXXX
方法,您将如何显示您的 "book" 数据。答案大概是让您的书自行显示:
MyUserInterface interface=...;
...
book.renderToUserInterface (interface);
我认为再次过度使用 get/set 方法的论点有一定的说服力——我认为好的设计可以使程序化 类 成为它们所代表的现实世界事物的良好模型,而现实世界中的事物通常不仅仅是可以设置和查询的离散数据项的存储库。我认为我们确实倾向于认为 类(在 Java 和其他语言中)不过是经过精心设计的数据结构,而且它们可能不止于此。
但是,在我看来,get/set 方法是 "evil" 的想法太过分了。教条地避免这些方法不太可能有帮助,特别是当大多数 OO 程序中发生的很多事情实际上是在支持模型域对象的 类 周围的基础结构时。此外,在考虑应用程序的完整 OO 模型时,"making the object do the work" 最有意义。在 个人 对象的设计层面,例如用于通用库,我认为我们必须有点务实。
我似乎记得 "make the object do the work" 是大约十年前的一个热门想法,但我认为这不再是一件大事了。
object 的属性与 object 的实现细节之间存在差异。
- 一本书有一个标题 - 这不是实现细节。
- 一本书有作者 - 这不是实现细节。
- 一本书的作者是如何存储的 - 这可以是一个实现细节。
Getter 并不邪恶,但您必须小心使用它们,因为它们可以公开限制对您的实现进行更改的实现细节。
class Book {
private ArrayList<Author> authors = new ArrayList<>();
public ArrayList<Author> getAuthors() { return authors; }
}
以上内容很糟糕,原因有二。首先,它 return 是对调用者可修改的 collection,允许调用者更改 collection。其次,它向调用者承诺 returned collection 是一个 ArrayList
.
Book book = ...;
ArrayList<Author> authors = book.getAuthors();
我们通过包装 collection:
解决了第一个问题class Book {
private ArrayList<Author> authors = new ArrayList<>();
public List<Author> getAuthors() {
return Collection.unmodifiableList(authors);
}
}
Book book = ...;
List<Author> authors = book.getAuthors();
现在调用者不能修改 collection,但他们仍然承诺 collection 是 List
。如果我们发现我们想要将我们的作者存储为 Set
(因为作者不会多次创作一本书),我们不能简单地更改内部存储。
class Book {
private HashSet<Author> authors = new HashSet<>();
public List<Author> getAuthors() {
return Collection.unmodifiableList(authors); // ERROR - authors not a list
}
}
我们必须将作者收集到一个新的 List
中,或者更改 getAuthors()
的签名,但这会影响希望 List
成为 returned.
相反,代码应该只是 return 一个 Collection
。这不会公开 authors
.
class Book {
public Collection<Author> getAuthors() {
return Collection.unmodifiableCollection(authors);
}
}
注意:可能是按作者顺序排列的,第一作者排在最前面。在这种情况下,您可能希望 return a List
向调用者保证数据实际上是有序的。在这种情况下,List
不是实现细节,而是接口契约的一部分。
那么,getTitle()
会破坏封装吗?不,绝对不是。
getAuthors()
会破坏封装吗?取决于它 return 的内容,以及您的承诺。如果它 return 是 Collection
,那么不会。如果它 return 是 List
并且您不承诺订购结果,那么可以。
这只是对一些不同但相关(有时是高级)主题的辅助评论,并不是对问题的直接回答(其他答案中已经很好地回答了)。也许这里的信息与这里或您的问题无关,如果是这样,请忽略它:-)
关于不可变性,即不添加二传手
Getter 通常很好,因为调用者无法更改对象,但不必要的 setter 会使推理对象变得更加困难,尤其是在编写并发代码时。
当你有 setter 时,对象的变化源可以来自更广泛的区域,另一个 class 甚至另一个线程。
参见 Immutable Objects in the Java tutorials and a synchronized sample with setters which is just plain more complicated and potentially error prone vs an immutable version without setters。
JavaFX Color class 是 JDK.
中不可变 class 的一个例子一般来说,当我创建一个 class 时,我通常会尝试将所有输入都放入构造函数参数中,使 class 最终化,而不是添加设置器并使 class决赛。你不能总是那样做,但当你可以时,它似乎让编程对我来说更容易。
请注意,setter 通常是有用和必要的,所以如果需要它们,请不要担心添加它们,不变性只是有时需要的属性,而不是规则。
关于桥接数据模型和显示
如果您真的对从要显示的对象获取数据的不同模式和约定感兴趣,请阅读 Martin Fowler 的 GUI Architectures,因为它对此提供了很好的概述。
通常,您想要 separation of concerns from the data and domain objects and the UI. For small apps, you don't need that separation and it is just more overhead. But, as soon as you start developing larger apps, it usually becomes a lot better organized if you separate the UI from the domain model completely. Usually, observables help to do this, often coupled with a design pattern like MVC, MVP or MVVM。
关于 JavaFX 属性和绑定到显示器
如果使用 JavaFX,正如您在问题中提到的,properties and binding provide an observable interface so a change in your domain object can be reflected automatically in your UI. You can define the properties directly in your data and domain classes. You can define your UI using something like FXML and an FXML Controller. In the controller you can bind properties of the UI (e.g. the text string of a Label) 到数据和域对象中的属性。这样,如果您在内部更改域中 属性 的值,例如图书馆中的书籍数量,您可以将该数字公开为 属性 每当添加新书时它会在 UI 中自动更新(无需明确告诉 UI添加图书时更新标签)。
例如在您的 LibraryController 中,您可能有:
@FXML
Label numberOfBooksInLibraryLabel;
Library library = new Library();
...
numberOfBooksInLibraryLabel.textProperty().bind(
library.books().sizeProperty().asString()
);
关于 JavaFX 属性和封装
JavaFX 有一些关于 JavaFX 属性的约定,这些约定比没有 JavaFX 的普通 Java 更复杂和微妙。为了帮助封装和 JavaFX 属性,请考虑使用 FXCollections.unmodifiableObservableList()
and read only properties。
private final ReadOnlyDoubleWrapper size = new ReadOnlyDoubleWrapper();
public final double getSize() {
return size.get();
}
public final ReadOnlyDoubleProperty sizeProperty() {
return size.getReadOnlyProperty();
}