巩固您的Java技能:深入了解良好软件设计的原理
#编程 #设计 #solid #java

作为具有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类是开放的(我们可以创建扩展它的新类,例如CircleSquare),但要进行修改(我们不需要更改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,即使它可能不需要。在一个很好的示例中,DrawableResizable接口被隔离,并且仅由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类。

要遵守依赖性反转原则,我们可以为数据访问创建一个抽象,并使UserServiceDataAccess同时取决于该抽象:

// 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
    }
}

现在,UserServiceDatabaseDataAccess类都取决于DataAccess抽象,从而可以更灵活和易于维护。它还使将来添加更多数据搜索实现,例如WebservicedataAccess或CacheddataAccess。


坚固的原理,固化。我们学会了如何保持课程的重点,开放新功能并进行修改,可互换,根据特定需求量身定制并脱钩。所有撒上爪哇。愉快的编码!