SOLID、KISS、YAGNI 和 DRY 原则
坚硬的
罗伯特·C·马丁和迈克尔·费瑟斯提出了这一原则,旨在鼓励我们创建更易于维护、更易于理解和更灵活的软件。该原则包含5个子原则:
- 单一责任原则(SRP)
- 开/闭原理(OCP)
- 里氏替换原理(L SP)
- 界面隔离原理(ISP)
- 依赖倒置原理(D IP)
单一职责原则(SRP)
如果一个类承担多个职责,那么更改其中一项职责可能会影响其他职责。
❌违反SRP:
public class Animal {
public void catSays() {
System.out.println("I am a cat.");
}
public void lionSays() {
System.out.println("I am a lion.");
}
public void hippoSays() {
System.out.println("I am a hippo.");
}
}
✔️遵循建议零售价:
public abstract class Animal {
public abstract void makeSound();
}
public class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("I am a cat.");
}
}
public class Lion extends Animal {
@Override
public void makeSound() {
System.out.println("I am a lion.");
}
}
public class Hippo extends Animal {
@Override
public void makeSound() {
System.out.println("I am a hippo.");
}
}
开闭原理 - OCP
该原则规定,如果存在一个新函数,你不应该修改或添加到现有的类中,而应该编写另一个类来扩展现有的类。
课程应该允许扩展,但不允许修改。
❌违反OCP:
public class Animal {
private String type;
public Animal(String type) {
this.type = type;
}
public void draw() {
if (type.equalsIgnoreCase("cat")) {
System.out.println("Drawing a cat");
} else if (type.equalsIgnoreCase("lion")) {
System.out.println("Drawing a lion");
}
// More animals can be added here, violating OCP
}
}
✔️遵循OCP:
public abstract class Animal {
public abstract void draw();
}
public class Cat extends Animal {
@Override
public void draw() {
System.out.println("Drawing a cat");
}
}
public class Lion extends Animal {
@Override
public void draw() {
System.out.println("Drawing a lion");
}
}
// You can add more animal classes without modifying existing code
里氏替换原理 - LSP
该原则规定,继承自父类的子类可以替换父类,而不会影响程序的正确性。
子类应该能够处理与父类相同的请求并给出相同的结果,或者给出相同类型的结果。
❌违反LSP:
public class Animal
{
public void run()
{
System.out.println("Run...");
}
public void fly()
{
System.out.println("Fly...");
}
}
public class Bird extends Animal
{
// Bird can fly and run...
}
public class Cat extends Animal
{
// Cat can't fly...
}
✔️ 遵循 LSP:
public interface Flyable {
public void fly();
}
public class Animal
{
public void run()
{
System.out.println("Run...");
}
}
public class Bird extends Animal implements Flyable
{
@Override
public void fly()
{
System.out.println("Fly...");
}
}
public class Cat extends Animal
{
}
接口隔离原则 - ISP
这条原则规定,接口不应包含过多需要实现的方法。如果接口过大,则应将其拆分为多个处理不同功能的较小接口。
任何代码都不应该被迫依赖它未使用的方法。类应该只执行履行其职责所必需的操作。
❌ 违反互联网服务提供商 (ISP) 规定:
interface Animal {
List<Animal> getAll();
get(String id);
save(Animal animal);
update(String id, Animal animal);
delete(String id);
getAllWithPaginate(int page, int size);
getAllWithSort(String sortCriteria);
/* ... */
}
✔️ 关注 ISP:
interface CrudAnimal {
List<Animal> getAll();
get(String id);
save(Animal animal);
update(String id, Animal animal);
delete(String id);
}
interface PagingAndSortingAnimal {
getAllWithPaginate(int page, int size);
getAllWithSort(String sortCriteria);
}
依赖倒置原理(DIP)
这一原则规定:
- 高层模块不应该依赖于底层模块。两者都应该依赖于抽象概念。
- 抽象概念不应依赖于细节,细节应依赖于抽象概念。
该原则的核心在于避免依赖模块(即在编码过程中容易更改的特定组件),而应依赖抽象组件,因为这些组件的变更可能性较小。应用和实现该原则的方法是,由高层模块定义接口,然后由底层模块实现这些接口。
❌ 违反DIP:
// Abstraction
interface Animal {
void makeSound();
}
// Low-level Module
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("I am a cat");
}
}
// Low-level Module
class Lion implements Animal {
@Override
public void makeSound() {
System.out.println("I am a lion");
}
}
// Low-level Module
class Hippo implements Animal {
@Override
public void makeSound() {
System.out.println("I am a hippo");
}
}
// High-level Module
class AnimalFactory {
// High-level modules depend on low-level modules
private final Cat animal;
public AnimalFactory() {
this.animal = new Cat();
this.animal.makeSound();
}
public Cat getAnimal() {
return this.animal;
}
}
public class Main {
public static void main(String[] args) {
AnimalFactory factory = new AnimalFactory();
}
}
✔️ 遵循 DIP:
// Abstraction
interface Animal {
void makeSound();
}
// Low-level Module
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("I am a cat");
}
}
// Low-level Module
class Lion implements Animal {
@Override
public void makeSound() {
System.out.println("I am a lion");
}
}
// Low-level Module
class Hippo implements Animal {
@Override
public void makeSound() {
System.out.println("I am a hippo");
}
}
// High-level Module
class AnimalFactory {
// High-level modules depend on abstractions
private final Animal animal;
public AnimalFactory(Animal animal) {
this.animal = animal;
this.animal.makeSound();
}
public Animal getAnimal() {
return this.animal;
}
}
public class Main {
public static void main(String[] args) {
Animal animal = new Cat();
AnimalFactory factory = new AnimalFactory(animal);
}
}
保持简单,笨蛋——KISS
凯利·约翰逊提出了这一原则,旨在强调代码简洁性的重要性。代码越简洁,阅读和理解的速度就越快,维护和修改也就越容易,这将有助于节省大量时间。
KISS原则的几种运用方式:
- 除非必要,否则不要滥用设计模式或库。
- 将大问题分解成小问题来处理。
- 明确命名变量和方法。
你不需要它 - YAGNI
这条原则由肯特·贝克提出。它强调不要用对未来的假设来复杂化需求。换句话说,不要在需要使用软件之前就假设并构建其功能。
不要重复自己 - 干
DRY(Don't Repeat Yourself,不要重复自己)是编程行业中一个为人熟知的核心原则,它强调尽可能地重用代码。该原则由 Andrew Hunt 和 David Thomas 提出。
这一原则使得代码的重复性降低,从而更容易、更快速地更改代码段。
为了实现这一原则,每当有一段代码在不同的地方被使用了两次,你就应该重新打包这段代码(创建函数、创建类……),以便以后可以调用它。
参考
文章来源:https://dev.to/nknghiem/solid-kiss-yagni-and-dry-principles-ie7




