作为具有4年以上经验的软件工程师,我遇到了职业生涯中的许多原则和最佳实践。我学到的最重要的一组原则之一是扎实。
稳固的立场是单一责任原则,开放式原则,Liskov替代原则,界面隔离原理和依赖性反演原则。这些原则正确应用时可能会导致更可维护和可扩展的代码。
在Javað中应用坚实的原则
S-单一责任原则
“单一责任原则”(SRP)指出,班级应该有一个,只有一个理由改变。换句话说,班级应该有一个明确的责任。该原则有助于使我们的代码更加可维护,可测试且易于理解。
这是如何应用SRP的一个示例:
class Employee {
private String name;
private String address;
private String email;
// The class has only one responsibility: to store employee information
public void setName(String name) { this.name = name; }
public void setAddress(String address) { this.address = address; }
public void setEmail(String email) { this.email = email; }
public String getName() { return name; }
public String getAddress() { return address; }
public String getEmail() { return email; }
}
class EmployeeService {
// This class has a single responsibility: to manage employee information
public void saveEmployee(Employee employee) {
// save employee to the database
}
public Employee findEmployee(int id) {
// find employee from the database
}
}
ð,如您所见,Employee
类具有一项责任:存储员工信息。它只有Getters和Setters方法,并且没有任何能做的方法。
EmployeeService
类还负有一项责任:管理员工信息。它有两种方法,保存并找到一个员工。
这种责任的分离使我们的代码更加可维护,因为如果我们需要更改存储员工信息的方式,我们只需要更改Employee
类,而不是EmployeeService
类。而且,如果我们需要更改管理员工信息的方式,我们只需要更改EmployeeService
类。
o-开放原则
该原则指出,应该开放一个类以进行扩展,但要修改。换句话说,在不必更改现有代码的情况下,在类中添加新功能应该很容易。
这是一个示例:
class Shape {
public void draw() {
// implementation
}
}
class Circle extends Shape {
@Override
public void draw() {
// implementation
}
}
class Square extends Shape {
@Override
public void draw() {
// implementation
}
}
ð在此示例中,Shape
类是开放的(我们可以创建扩展它的新类,例如Circle
和Square
),但要进行修改(我们不需要更改Shape
类,为了添加新功能)。
这很好,因为它允许灵活性和可维护性。如果我们需要添加一个新形状,我们可以创建一个新类,该类无需更改现有代码而扩展Shape
。这也使添加新功能变得容易而不必担心破坏现有代码。
重要的是要注意,开放闭合原理不仅适用于类,还适用于函数,模块甚至系统。
L- liskov替代原则
Liskov替代原则(LSP)指出,超类的对象应能够用子类的对象替换而不会影响程序的正确性。换句话说,子类应该能够为自己的父班而不会引起任何问题。
这是如何应用此原理的一个示例:
class Bird {
public void fly() {
System.out.println("I can fly");
}
}
class Ostrich extends Bird {
@Override
public void fly() {
throw new UnsupportedOperationException("I can't fly");
}
}
ð在此示例中,我们有一个带有fly()
方法的Bird
类,该方法打印了“我可以飞”。我们还有一个Ostrich
类,可以扩展Bird
类。 Ostrich
类覆盖了fly()
方法并引发异常,因为鸵鸟不能飞。
由于Liskov替代原则,我们知道我们可以用Bird
类的实例替换Ostrich
类的实例而不会引起任何问题。
这一原则是好的,因为它有助于我们确保代码强大且可维护。通过遵循Liskov替代原则,我们可以确信,我们创建的任何子类都将与父班以及与其他依赖的其他类无缝合作。
I-界面隔离原理
“接口隔离原则”指出,“不应强迫客户实施他们不使用的接口”。换句话说,这是为了确保接口小巧而具体,而不是大而大。该原则有助于促进代码重用和可维护性。
这是如何应用此原理的一个示例:
// BAD example - interface is not segregated and forces implementation of unnecessary methods
interface Shape {
void draw();
void resize();
}
class Square implements Shape {
public void draw() {
// implementation
}
public void resize() {
// implementation
}
}
// GOOD example - interface is segregated and only forces implementation of necessary methods
interface Drawable {
void draw();
}
interface Resizable {
void resize();
}
class Square implements Drawable, Resizable {
public void draw() {
// implementation
}
public void resize() {
// implementation
}
}
ð在坏示例中,Shape
接口不会被隔离,并且迫使Square
类实现resize()
Method,即使它可能不需要。在一个很好的示例中,Drawable
和Resizable
接口被隔离,并且仅由Square
类实现了必要的方法。
通过遵循此原则,我们可以创建更具体且易于使用的接口,从而可以在我们的代码库中更好地维护性和灵活性。
D-依赖性反转原理
依赖性反转原理(d中的d)指出,高级模块不应取决于低级模块,而是两者都应取决于抽象。这允许我们的代码中的灵活性和易于维护。
这是如何应用此原理的一个示例:
// High-level module
class UserService {
private DataAccess dataAccess;
public UserService(DataAccess dataAccess) {
this.dataAccess = dataAccess;
}
public User getUser(int id) {
return dataAccess.getUser(id);
}
}
// Low-level module
class DataAccess {
public User getUser(int id) {
// Code to retrieve user from database
}
}
ð在此示例中,我们的高级UserService
类取决于低级DataAccess
类。如果我们需要更改访问数据的方式,这可能会导致问题,因为这需要更改UserService
类。
要遵守依赖性反转原则,我们可以为数据访问创建一个抽象,并使UserService
和DataAccess
同时取决于该抽象:
// Abstraction
interface DataAccess {
User getUser(int id);
}
// High-level module
class UserService {
private DataAccess dataAccess;
public UserService(DataAccess dataAccess) {
this.dataAccess = dataAccess;
}
public User getUser(int id) {
return dataAccess.getUser(id);
}
}
// Low-level module
class DatabaseDataAccess implements DataAccess {
public User getUser(int id) {
// Code to retrieve user from database
}
}
现在,UserService
和DatabaseDataAccess
类都取决于DataAccess
抽象,从而可以更灵活和易于维护。它还使将来添加更多数据搜索实现,例如WebservicedataAccess或CacheddataAccess。
坚固的原理,固化。我们学会了如何保持课程的重点,开放新功能并进行修改,可互换,根据特定需求量身定制并脱钩。所有撒上爪哇。愉快的编码!