开发中需要遵守的设计原则?

设计模式中主要有六大设计原则,简称为SOLID,是由于各个原则的首字母简称合并的来(两个L算一个,solid 稳定的),六大设计原则分别如下:

1、单一职责原则
单一职责原则的定义描述非常简单,也不难理解。一个类只负责完成一个职责或者功能。也就是说在类的设计中我们不要设计大而全的类,而是要设计粒度小、功能单一的英。
比如 我们设计一个类里面既包含了用户的一些操作,又包含了支付的一些操作,那这个类的职责就不够单一,应该将该类进行拆分,拆分成多个功能更加单一的,粒度更细的类.

单一职责原则要求一个类只负责单一功能,从而提高代码的内聚性,减少代码的耦合性。

// 不遵守单一职责原则的例子
public class Animal {
    public void eat() {
        System.out.println("吃食物");
    }

    public void fly() {
        System.out.println("飞行");
    }

    public void swim() {
        System.out.println("游泳");
    }
}

// 遵守单一职责原则的例子
public class Animal {
    public void eat() {
        System.out.println("吃食物");
    }
}

public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

public class Bird implements Flyable {
    @Override
    public void fly() {
        System.out.println("鸟在飞行");
    }
}

public class Fish implements Swimmable {
    @Override
    public void swim() {
        System.out.println("鱼在游泳");
    }
}

在不遵守单一职责原则的Animal类中,一个类负责了吃、飞、游泳三个不同的功能,导致类的职责不够清晰,代码也比较混乱。而遵守单一职责原则的Animal类只负责吃的功能,同时定义了Flyable和Swimmable两个接口分别用于定义飞行和游泳的功能,从而将职责分离,代码更加清晰明了。

2、开放封闭原则
定义:对扩展开放,对修改关闭
对扩展开放和对修改关闭表示当一个类或一个方法有新需求或者需求发生改变时应该采用扩展的方式而不应该采用修改原有逻辑的方式来实现。因为扩展了新的逻辑如果有问题只会影响新的业务,不会影响老业务;而如果采
用修改的方式,很有可能就会影响到老业务受影响。

优点:

  1. 新老逻辑解耦,需求发生改变不会影响老业务的逻辑
  2. 改动成本最小,只需要追加新逻辑,不需要改的老逻辑
  3. 提供代码的稳定性和可扩展性

开放封闭原则(Open Closed Principle)指的是软件实体(类、模块、函数等)应该可以扩展,但是不可修改。也就是说,在增加新功能时,不需要修改原有的代码,而是通过扩展来实现。

public interface Shape {
    public void draw();
}

public class Circle implements Shape {
    public void draw() {
        System.out.println("Circle draw method.");
    }
}

public class Rectangle implements Shape {
    public void draw() {
        System.out.println("Rectangle draw method.");
    }
}

public class ShapeFactory {
    public static Shape createShape(String shapeType) {
        if (shapeType.equalsIgnoreCase("circle")) {
            return new Circle();
        } else if (shapeType.equalsIgnoreCase("rectangle")) {
            return new Rectangle();
        } else {
            return null;
        }
    }
}

public class Client {
    public static void main(String[] args) {
        Shape shape1 = ShapeFactory.createShape("circle");
        Shape shape2 = ShapeFactory.createShape("rectangle");
        shape1.draw();
        shape2.draw();
    }
}

在这个示例中,我们定义了一个 Shape 接口和两个实现了该接口的类 Circle 和 Rectangle,然后通过 ShapeFactory 工厂类来创建不同类型的图形对象,而客户端只需要使用工厂类创建对象并调用其 draw() 方法,无需关心具体创建过程和实现细节,实现了开放封闭原则。如果需要添加新的图形类型,只需要实现 Shape 接口即可,而不需要修改原有的代码。

3、里氏替换原则

要理解里氏替换原则,其实就是要理解两个问题:

1)什么是替换?
替换的前提是面向对象语言所支持的多态特性,同一个行为具有多个不同表现形式或形态的能力。

2)什么是与期望行为一致的替换?
在不了解派生类的情况下,仅通过接口或基类的方法,即可清楚的知道方法的行为,而不管哪种派生类的实现,都与接口或基类方法的期望行为一致。

不需要关心是哪个类对接口进行了实现,因为不管底层如何实现,最终的结果都会符合接口中关于方法的描述(也就是与接口中方法的期望行为一致)。
或者说接口或基类的方法是一种契约,使用方按照这个契约来使用,派生类也按照这个契约来实现。这就是与期望行为一致的替换。

里氏替换原则(Liskov Substitution Principle)是面向对象设计中的一条重要原则,它指出“子类对象可以替换其父类对象,而程序不会产生错误或异常”。也就是说,在一个系统中,子类可以替换其父类,而不会影响程序的正确性。以下是一个 Java 代码示例:

public class Animal {
    public void move() {
        System.out.println("Animal is moving");
    }
}

public class Bird extends Animal {
    @Override
    public void move() {
        System.out.println("Bird is flying");
    }

    public void fly() {
        System.out.println("Bird is flying");
    }
}

public class Dog extends Animal {
    @Override
    public void move() {
        System.out.println("Dog is running");
    }

    public void bark() {
        System.out.println("Dog is barking");
    }
}

public class Test {
    public static void main(String[] args) {
        Animal bird = new Bird();
        Animal dog = new Dog();

        bird.move();
        dog.move();
    }
}

在上面的示例中,Bird 和 Dog 都是 Animal 的子类,并且都重写了 Animal 中的 move() 方法。在 Test 类的 main() 方法中,我们创建了一个 Bird 对象和一个 Dog 对象,并分别调用它们的 move() 方法,由于使用了里氏替换原则,所以程序可以正常运行并输出正确的结果。

4、接口隔离原则

定义:要为各个类建立它们需要的专用接口,而不要试图去建立一个很庞大的接口供所有依赖它的类去调用。
接口隔离原则与单一职责原则的区别
接口隔离原则和单一职责都是为了提高类的内聚性、降低它们之间的耦合性,体现了封装的思想,但两者是不同的:

  1. 单一职责原则注重的是职责,而接口隔离原则注重的是对接口依赖的隔离。
  2. 单一职责原则主要是约束类,它针对的是程序中的实现和细节;接口隔离原则主要约束接口,主要针对抽象和程序整体框架的构建。
// 接口隔离原则之后
public interface Animal {
    void eat();
}

public interface Flyable {
    void fly();
}

public interface Swimmable {
    void swim();
}

public class Bird implements Animal, Flyable {
    public void eat() {
        // 鸟的吃法
    }
    public void fly() {
        // 鸟的飞行方式
    }
}

public class Fish implements Animal, Swimmable {
    public void eat() {
        // 鱼的吃法
    }
    public void swim() {
        // 鱼的游泳方式
    }
}

通过将Animal接口拆分为多个更小的接口,即接口隔离原则,可以避免Bird类实现与其无关的Swimmable接口,而Fish类也不需要实现与其无关的Flyable接口,从而实现了代码的高内聚低耦合。

5、依赖倒置原则

定义:依赖倒置原则(Dependence Inversion Principle, DIP)是指在设计代码架构时,高层模块不应该依赖于底层模块,二者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
依赖倒置原则是实现开闭原则的重要途径之一,它降低了客户与实现模块之间的耦合。
依赖倒置原则的好处:

  • 减少类间的耦合性,提高系统的稳定性.(根据类与类之间的耦合度从弱到强排列:依赖关系、关联关系、聚合关系、组合关系、泛化关系和实现关系)
  • 降低并行开发引起的风险(两个类之间有依赖关系,只要制定出两者之间的接口(或抽象英)就可以独立开发了)
  • 提高代码的可读性和可维护性

依赖倒置原则(Dependency Inversion Principle,DIP)是指高层模块不应该依赖低层模块,二者都应该依赖其抽象。抽象不应该依赖细节,细节应该依赖抽象。简而言之,依赖倒置原则就是要面向接口编程,而不是面向实现编程。

假设我们有一个 Person 类,它有一个 phone 属性,表示电话号码。我们还有两个类 AndroidPhone 和 IPhone,分别实现了 Phone 接口,表示 Android 手机和 iPhone。Person 类依赖于 Phone 接口,而不依赖具体的 AndroidPhone 或 IPhone 类。

public interface Phone {
    void call();
}

public class AndroidPhone implements Phone {
    public void call() {
        System.out.println("Calling from Android Phone");
    }
}

public class IPhone implements Phone {
    public void call() {
        System.out.println("Calling from iPhone");
    }
}

public class Person {
    private Phone phone;

    public Person(Phone phone) {
        this.phone = phone;
    }

    public void makePhoneCall() {
        phone.call();
    }
}

public class Main {
    public static void main(String[] args) {
        Phone androidPhone = new AndroidPhone();
        Person person1 = new Person(androidPhone);
        person1.makePhoneCall();

        Phone iPhone = new IPhone();
        Person person2 = new Person(iPhone);
        person2.makePhoneCall();
    }
}

在上面的代码中,Person 类通过构造函数接收 Phone 接口,而不是具体的 AndroidPhone 或 IPhone 类。这样,当我们需要使用不同的手机类型时,只需要实现 Phone 接口,并将实现类传递给 Person 类即可,不需要修改 Person 类的代码。这样就实现了依赖倒置原则。

6、迪米特法则

迪米特法则(Law of Demeter,LoD)又叫最少知识原则(Least Knowledge Principle,LKP),是指一个对象应当对其他对象有尽可能少的了解,不和陌生人说话。
简单来说迪米特法则想要表达的思想就是:不该有直接依赖关系的类之间,不要有依赖;有依赖关系的类之间,尽量只依赖必要的接口。

如果两个软件实体无须直接通信,那么就不应当发生直接的相互调用,可以通过第三方转发该调用。其目的
是降低类之间的耦合度,提高模块的相对独立性。

迪米特法则的核心思想是降低类之间的耦合度,使得各个类可以独立地进行设计、开发和测试。它要求一个对象应该对其他对象有最少的了解,即一个类应该对自己需要耦合或调用的类知道得最少,被耦合或调用的类也应该尽量降低对外部类的依赖。

在实际开发中,迪米特法则可以体现在以下几个方面:

  1. 类与类之间的关系越密切,耦合度越大,一个类依赖于另一个类的变化也越大。因此,要尽量降低类与类之间的关系。
  2. 如果两个类不必彼此直接通信,那么这两个类就不必发生直接的相互作用,而是可以通过第三者转发消息。换言之,就是如果两个类之间没有必然的耦合关系,那么就不应该发生任何的直接相互调用,而是通过一个第三者来转发调用。
  3. 对于一个系统的设计来说,多使用组合、聚合、依赖等关系来实现,可以降低系统的耦合度,使系统更加灵活、易于扩展。
public class PizzaStore {

    private void takeOrder() {
        System.out.println("披萨店接收订单");
    }

    private void prepareSource() {
        System.out.println("披萨店准备披萨制作原料");
    }

    private void cookPizza() {
        System.out.println("披萨店烹制披萨");
    }

    private void packPizza() {
        System.out.println("披萨店打包披萨");
    }

    private void deliveryPizza() {
        System.out.println("披萨店配送披萨");
    }

    public void orderPizza() {
        takeOrder();
        prepareSource();
        cookPizza();
        packPizza();
        deliveryPizza();
    }
}
//定披萨代理类
public class PizzaStoreProxy {
    private PizzaStore pizzaStore;

    public PizzaStoreProxy(PizzaStore pizzaStore) {
        this.pizzaStore = pizzaStore;
    }

    public void orderPizza() {
        pizzaStore.takeOrder();
        pizzaStore.prepareSource();
        pizzaStore.cookPizza();
        pizzaStore.packPizza();
        pizzaStore.deliveryPizza();
    }
}
//客户类
public class Customer {

    public void orderPizza(PizzaStoreProxy pizzaStoreProxy){
        pizzaStoreProxy.orderPizza();
    }

}
public class Test{
  public static void main(String[] args){
        Customer xiaoming = new Customer();
        PizzaStore pizzaStore = new PizzaStore();
        PizzaStoreProxy pizzaStoreProxy = new PizzaStoreProxy(pizzaStore);
        xiaoming.orderPizza(pizzaStoreProxy);
    }
}

可以看到通过引入一个代理类,客户现在只跟披萨店代理打交道,完全不关披萨店的事,也不知道披萨店的内部实现,实现了解耦。其实这个代理类这就好比现在的美团,我们只在美团下披萨外卖订单,其他事就不需要我们管了,比如:如何做披萨、如何送披萨等等。美团在这里就起到代理的作用。

7 合成复用原则

合成复用原则(Composite Reuse Principle,CRP)指尽量使用对象组合,而不是继承来达到复用的目的。使用继承会使得原有类的功能加入新功能时变得很复杂,而且继承破坏了类的封装性,使得子类与父类之间耦合度增强,不利于程序的扩展和维护。

// 音频播放器类
public class AudioPlayer {
    private Audio audio;

    // 构造函数,接收Audio类对象作为参数
    public AudioPlayer(Audio audio) {
        this.audio = audio;
    }

    // 播放音频的方法
    public void play() {
        // 使用成员变量的方法实现自己的功能
        audio.playAudio();
    }
}

// 音频类
public class Audio {
    // 播放音频的方法
    public void playAudio() {
        // 实现播放音频的功能
        System.out.println("Playing audio...");
    }
}

在上面的例子中,音频播放器类(AudioPlayer)使用了合成复用原则,将音频类(Audio)作为自己的成员变量,并通过调用音频类的方法来实现自己的功能。这样,当需要扩展播放器类的功能时,只需要增加新的成员变量并调用其方法即可,而不需要修改原有的代码。这样可以有效地降低代码的耦合度,提高代码的复用性和可维护性。

软件开发中我们要基于这七个原则,设计建立稳定、灵活、健壮的程序。

  • 4
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值