它用于商业项目。
Architecture
Business Object
过去,我们的体系结构由称为“业务对象”的类组成(它也有一些其他名称,但思想是相同的),它是包含逻辑(函数)和存储值(又名字段)的类的类型。
例如,假设我们有一个管理客户的系统。
public class Customer {
private String age;
private String name;
private String prefix;
// setter and getters goes here...
public void showMe() { // some logic
System.out.println("My name is "+name);
}
}
它适用于小型项目。 经常找到有关此类课程的书籍和手册。 但是它们不具有可伸缩性,并且会带来一些麻烦。 因此,我们将该类分为两部分:
Anemic Object aka Model
这是一个存储值的类,它应该缺少逻辑。
public class Customer {
private String age;
private String name;
private String prefix;
// setter and getters goes here...
}
这是我们数据库中的类
这是我们通过休息服务班
{"age":10,"name":"John","prefix":"Phd"}
它可能有逻辑,但不建议这样做。
Service Class
与Model类相反,服务类缺少包含逻辑(方法/功能)的字段。
public class CustomerService {
public void showMe() {
System.out.println("My name is "+name);
}
}
Why we split the class?.
这是因为易于调试和维护代码。 它还有助于在不破坏其他代码的情况下升级项目并添加新功能。
例如,假设我们要添加连接到数据库的方法
public class CustomerMySql { // usually it is called CustomerRepo etc.
public List<Customer> listAll() {
// our code
}
}
它是什么?。 服务类。 实际上,我们可以拥有尽可能多的服务类。
因此,我们也将服务类分为几类,通常是:
- 存储库,DAO,DAL类(连接到数据库)Web服务类。逻辑类(例如验证,工厂等)其他。
再说一次,为什么呢? 因为它很容易调试和维护代码。 假设我们有一个问题,我们的系统无法将客户插入数据库。 因此,我们找到了名称空间(MySql),然后找到了以Customer开头的类并找到了方法。
Question: But what about setter and getter?.
好吧,在我们的Model类中,我们添加了逻辑,这种逻辑在大多数情况下是无用的!
这是逻辑:
public class Customer {
// ....
public String getAge() {
return age;
}
public void setAge(String age) {
this.age = age;
}
}
我们可以使用Lombok(强烈建议使用)将其隐藏,但是这仍然是逻辑。
@Getter @Setter // lombok
public class Customer {
private String age;
private String name;
private String prefix;
// we don't need setter and getter.
}
Lombok在编译时起作用,因此在编译之前添加代码是相同的(但是仍然要添加代码)。
Question: But OOP
但是OOP需要封装。
OOP不是法律,而是法律。
Question: What is the problem with setter and getter?
代码的清晰度。
这就是我们如何使用带有setter和getter的模型。
Customer cus=new Customer();
cus.setName("John");
System.out.println("The age is "+cus.getAge());
这是带有公共字段的版本。
Customer cus=new Customer();
cus.name="John";
System.out.println("The age is "+cus.age);
Question: We couldn't add logic with public fields, are we?
假设下一个代码
public void setName(String name) {
this.name = name;
this.prefix="Junior";
}
因此,如果我们修改名称,那么我们也会修改前缀。 在setter和getter中添加逻辑的问题并不明显。
例如:
Customer cus=new Customer();
cus.setPrefix("Dr.");
cus.setName("John");
// it will return Junior John instead of Dr. John.
给setter和getter添加逻辑通常是邪恶的。
另外,我们可以在易于调试和测试的服务类中编写逻辑。
Question: We should encapsulate the values.
是的,但是不能通过设置方法和获取方法来解决!
例如,假设我们的模型包含一个新字段(这是一个对象)
public class Customer {
private String age;
private String name;
private String prefix;
private Category category;
// setter and getters
}
public class Category {
private String nameCategory;
// setter and getters
}
例如,假设我们要修改类别内的名称:
Customer cus=new Customer();
cus.setName("John");
cus.getCategory().setNameCategory(""); // Using get to set a value @_@.
因此,我们的getter不仅缺少封装(我们正在使用get修改字段),而且它也不干净。
Question: Then, how we could encapsulate values?.
首先,每个(JAVA,但也适用于其他语言)开发人员必须了解原始对象与对象之间的区别以及按值和按引用之间的区别。
我们也可以通过创建克隆来封装值,但是出于明显的原因我们不这样做。
另外,如果我们读取的值必须是不可变的,那么为什么要修改它呢? 在这里我们应用SRP(简单责任原则),我们同时执行一项任务:或者我们修改值,或者读取值,而不是两者。
We couldn't do Unit test without setter and getter.
我经常听到
我们不能对生成的代码进行单元测试(因为它是作弊!)。 另外,我们不能对琐碎的代码进行单元测试。 它影响代码覆盖率,但是,代码覆盖率只是一个数字,而不是(确实)有价值的度量。 许多开发人员通过人为地增加代码覆盖率来发挥系统作用。
We couldn't use Interface without setter and getter.
接口非常有用,因为我们可以重用代码。
一些Java编码器创建一个Interface = One类,这很错误,但我不是在谈论它。
关于SOLID(I =接口)
SOLID is a guideline, not a rule.
但是关于接口,假设我们有以下模型:
- 客户(年龄,姓名,前缀)员工(年龄,姓名,公司)
因此,如果不是继承,则创建接口是有意义的。 (提示:不是真的)。
- 人(年龄,姓名)
所以我们的类被实现为
public class Customer implements Person {
// implementation
}
public class Employee implements Person {
// implementation
}
public interface Person {
String getName();
void setName(String name);
String getAge();
void setAge(String age);
}
但是,使用接口会增加DEPENDENCY。
现在,假设我们不想持有年龄的顾客。 如果我们修改接口,那么我们也修改类雇员,因此,我们发现了一个问题,因为我们添加了一个依赖项。
如果有明确的用途,则接口是正确的,但它也是一把双刃剑。
另外,很难使用Interface调试代码。
假设此代码失败:
SomeInterface object;
// it fails somewhere here.
问题:对象的类别是什么?
However
并非每个对象都是相似的。 例如,视觉对象,按钮:
对于视觉对象,我们不使用Model + Service类对,而是使用Bussiness Object类(具有字段和函数的类)。 为什么?。 因为它们比贫乏的模型+服务类更适合。
public class MyButton {
private String Title;
private int width;
private int height;
private int top;
private int left;
// setter and getter also functions
}
我们还可以向setter和getter添加逻辑。
public class MyButton {
//....
public int getXRight() {
return left+width; // we can use a getter with logic without a field.
}
public void setWidth(int width) {
if(width<100) {
width=100;
}
this.width = width;
}
}
Also
有时我们想标准化代码,即我们不想看到一个类的一种样式,而不想看到另一种样式的另一种样式。
例如,它是正确的(取决于上下文:
class Model1 {
public int field1;
public int field2;
}
class Model2 {
public int field3;
public int field4;
}
这也是对的
class Model1 {
private int field1;
private int field2;
// setter and getter goes here.
}
class Model2 {
private int field3;
private int field4;
// setter and getter goes here.
}
但事实并非如此。
class Model1 { // with setter and getters
private int field1;
private int field2;
// setter and getter goes here.
}
class Model2 { // with public fields
public int field3;
public int field4;
}
Also (more)
一些库要求使用setter和getter。 JSF过去依赖于setter和getter(但现在不再,我们可以使用公共字段)。
因此,没有一个万能的解决方案。
More about Java.
Java运行时引擎是偷偷摸摸的,并且它了解setter和getter。 它优化了结果代码,因此,如果我们添加常规的setter和getter(无需额外的逻辑),则JRE的行为与公共字段相同。
Final world.
但是,我们可以在公共领域使用模型类吗? 是。 C以这种方式(C不是OOP)和其他一些语言工作。
struct account {
int age;
char *name;
char *prefix;
};
我们通常使用setter和getter,因为它们是自动生成的(通过重构或Lombok),但是我们随后自动使用它,因此JIT编译器无论如何都将其删除。
JIT removes automatically most setter and getter that were generated, ahem automatically, so why are we adding?
People forget that (we) developers are (still) humans.
例如,我会重复我自己
object.getField().getOtherField().getOhNoesAnotherField().setFinalField("Some Name");
尚不清楚,而(使用公共字段)
object.field.otherField.ohNoesAnotherfield.finalField="Some Name";
这不仅写短,而且理解简单。
作为这样的注释代码:
object.getField().getOtherField().someMethod<Class,OtherClass>(arg,moreargs); // is cringe
C#通过取悦每个pro封装来解决它,而不是通过创建属性来反对封装。 因此,在C#中,我们使用了:
object.Field.OtherField.OhNoesAnotherField.FinalField="Some Name";
Java没有它,这很可惜。
Example
假设我们想向客户展示,但是我们需要一个新列(id),该列必须自动生成,并且无法在视图/模板层上生成。
我们不需要使用新的setter和getter来毒害我们的模型类。
public class CustomerUI extends Customer {
private int id;
public int getId() {
id=id+1;
return id;
}
}
因此,此类专门用于解决视觉问题。 我们可以删除Customer类的setter和getter方法,同时保留一些逻辑