一个类应该只负责一项职责,职责可大可小重点在于“单一”
举个栗子:有一个电饭煲类,他有煮饭、炒菜、播放音乐方法,看起来很强大,但当出现问题或需要新增修改方法时,就会面临杂乱困难。最好做法是电饭煲类只负责煮饭,铁锅类负责炒菜,音响类负责播放音乐
对于一个类,你想拓展方法但开闭原则要求不能修改源代码,那么就需要JAVA中接口或抽象类实现
举个栗子:我有一个快递服务类,其中有计价方法,目前我只与2个快递公司合作,于是我这样写:
public class Service {
public double calculateCost(String company, double weight) {
if ("SF".equals(company)) {
return weight * 1.5;
} else if ("ZT".equals(company)) {
return weight * 1.2;
}
return 0;
}
}
但是某一天,我又与新的快递公司合作了,那么拓展方法是calculateCost()末尾又加上else if吗?显然如果这么做,就违背了开放封闭原则,修改了源代码。所以我们可以通过接口实现:
public interface Service { // 定义快递服务接口
double calculateCost(double weight);
}
public class SFShippingCalculator implements Service {
public double calculateCost(double weight) {
return weight * 1.5;
}
}
public class ZTShippingCalculator implements Service {
public double calculateCost(double weight) {
return weight * 1.2;
}
}
public class YDShippingCalculator implements Service { // 新增快递公司时不触动源代码
public double calculateCost(double weight) {
return weight * 1.2;
}
}
重点在于替换,说白了父类能使用的地方,子类也能无缝衔接。任何子类都可以使用父类引用类型操作,如Animal bird = new Bird(),所谓无缝衔接意味着我们只需要知道bird是动物
举个栗子:动物都有自己的特性,老鼠会打洞,鸟会飞,意味着需要实现属于自己特性的方法,那我怎么调用鸟去飞呢?强转一下((Bird) bird).fly(),那问题来了,万一bird是狗呢?调用fly()会导致运行时异常
正确替换姿势,定义飞行动物接口,让会飞的动物都实现这个接口,在调用fly()的时候就可以先判断是不是会飞的动物,是会飞的动物再通过接口调用fly()
public interface FlyingAnimal {
void fly();
}
public class Bird extends Animal implements FlyingAnimal {
public void fly() {
System.out.println("起飞");
}
}
public static void main(String[] args) {
Animal bird = new Bird();
if (bird instanceof FlyingAnimal) {
((FlyingAnimal) bird).fly();
}
}
在原本相互依赖的类之间加一层抽象层,使得两个类分别依赖抽象层
举个栗子:我有一个咖啡店类,需要通过小米咖啡机类制作咖啡,于是在构造函数中new出小米咖啡机,并在openShop()方法中制作咖啡:
public class MiCoffeeMachine {
public void makeCoffee() {
System.out.println("小米咖啡机正在制作咖啡...");
}
}
public class CoffeeShop {
private MiCoffeeMachine miCoffeeMachine;
public CoffeeShop() {
this.miCoffeeMachine = new MiCoffeeMachine();
}
public void openShop() {
coffeeMachine.makeCoffee();
System.out.println("咖啡店开门了,制作咖啡完毕!");
}
}
显然上述代码,咖啡店类直接依赖了小米咖啡机类从而违背依赖倒置原则,违背就意味着我们后期将小米咖啡机更换为华为咖啡机的时候,需要修改CoffeeShop类。那么需要在二类之间加一层抽象
public interface CoffeeMaker {
void makeCoffee();
}
public class MiCoffeeMachine implements CoffeeMaker {
public void makeCoffee() {
System.out.println("小米咖啡机正在制作咖啡...");
}
}
public class HuaCoffeeMachine implements CoffeeMaker {
public void makeCoffee() {
System.out.println("华为咖啡机正在制作咖啡...");
}
}
public class CoffeeShop {
private CoffeeMaker coffeeMaker;
public CoffeeShop(CoffeeMaker coffeeMaker) {
this.coffeeMaker = coffeeMaker; // 依赖于抽象接口
}
public void openShop() {
coffeeMaker.makeCoffee();
System.out.println("咖啡店开门了,咖啡制作完毕!");
}
}
不应该强迫一个类去实现它不需要的接口功能,说白了当你的一个接口包含多个实现类用不到的方法,那么应该拆分接口方法,形成多个新的接口
举个栗子:有一个厨师接口,包含做披萨、煮意大利面、做沙拉方法。然后有一个披萨店类(只卖披萨)实现了厨师接口,但其中煮意大利面、做沙拉方法压根用不到,那么应该拆分为披萨厨师接口、意大利面厨师接口、 沙拉厨师接口
一个对象应该对其他对象有尽可能少的了解(别去打听你不该知道的事)
举个栗子:咖啡机对象类内部包含许多类对象,如热水管道类、喷嘴类等。如果咖啡店类在制作咖啡方法中使用了热水管道类等就违背了迪米特法则:
public class CoffeeShop {
private CoffeeMaker coffeeMaker;
private Water water; // CoffeeMaker内对象
private Nozzle nozzle; // CoffeeMaker内对象
public CoffeeShop(Water water,Nozzle nozzle) {
this.water = water;
this.Nozzle = nozzle;
}
public void openShop() {
// coffeeMaker.makeCoffee(); // 不直接调用咖啡机,而调用咖啡机内对象
water.heat();
nozzle.shut();
System.out.println("咖啡制作完毕");
}
}
优先使用聚合来复用代码,而不是通过继承
举个栗子:还是以Animal为例,我们可以定义飞行能力类Flyable,当某一种动物具备这个能力时,就将Flyable对象加进去:
public class Flyable {
public void fly() {
System.out.println("Flying...");
}
}
public class Bird extends Animal {
private Flyable flyable;
public Bird(Flyable flyable) {
this.flyable = flyable;
}
public void fly() {
if (flyable != null) {
flyable.fly();
} else {
System.out.println("没有飞行能力...");
}
}
}