java设计模式--六大原则
一、单一职责原则
单一职责原则:就一个类而言,应该仅有一个引起它变化的原因。通俗来说,就是互相不相关的属性和方法不要放在一个类中,就好比之前简单工厂模式中介绍的那样,客户端(Customer)应该与工厂(Factory)建立成两个类,当客户想要工厂中的另一种产品时,只需要修改客户端,再或者,工厂想要生产新产品,就只需在工厂类中添加,客户端的类而不需修改。这种只有一个动机的去改变一个类就是单一职责原则。
//产品接口 public interface Product { void run(); } public class Car implements Product { @Override public void run() { System.out.println("drive car"); } } public class Bicycle implements Product { @Override public void run() { System.out.println("ride on a bicycle"); } }
//工厂类 public class Factory { public static Product createProduct(String productName){ Product product = null; switch (productName){ case "car": product = new Car(); break; case "bicycle" : product = new Bicycle(); break; } return product; } }
//客户端 public class Customer { public static void main(String[] args) { Product car = Factory.createProduct("car"); car.run(); Product bicycle = Factory.createProduct("bicycle"); bicycle.run(); } }
二、里氏替换原则
里氏替换原则:子类型必须能够替换掉它们的父类型。其实就是在一个程序里,某一个地方使用的是一个父类,那么把父类换成它的子类同样适用。另外子类一般不该重写父类的方法,因为父类的方法一般都是对外公布的接口,是具有不可变性的,你不该将一些不该变化的东西给修改掉。因为一般我们认为,父类可以完成的事情,子类也可以,如果重写父类的方法并且因此出错,将来如果用子类替换父类就会出现问题。
三、依赖倒转原则
1.高层模块不应该依赖低层模块,两个都应该依赖抽象
2.抽象不应该依赖细节,细节应该依赖抽象
通俗来说就是依赖接口编程,就比如上面的简单工厂的例子,我们修改一下使其更直观一些,如果没有Product这个接口(如下所示),我们就必须去调用car.run(),此时必须传入一个Car对象,那么如果以后我们不想用Car想用Bicycle或者其他交通工具呢,那就得新增多个Drive类,所以最好的方法是建立一个Product接口,让所有产品都去实现这个接口,这样,客户端也不必去关心从哪个Drive类中获取所需要的run()方法,直接将想用的交通工具传进工厂类Factory中就可以了。
public class Car { public void run() { System.out.println("drive car"); } } public class Drive{ public static void goHome(Car car){ car.run(); } } public class Customer { public static void main(String[] args) { Car car = new Car(); Drive.goHome(car); } }
四、接口隔离原则
接口隔离原则:一个接口的行为应该尽可能的小,其实就是接口里的方法一定要是所有实现这个接口的类所能实现的。比如我们定义了一个Car接口,里面有两个方法,驾驶和导航,但是实际情况是并不是所有的汽车都有导航的功能,这样的话没有导航功能的汽车实现这个接口的时候就只能把导航的这个方法空着,所以我们最好把navigation()这个方法从这个接口中去掉,另外单独写一个接口。
public interface Car { //行驶 void run(); //导航 void navigation(); }
public class Car1 implements Car {
@Override
public void run() {
System.out.println("Car1 run ....");
}
@Override
public void navigation() {
}
}
public class Car2 implements Car {
@Override
public void run() {
System.out.println("Car2 run ...");
}
@Override
public void navigation() {
System.out.println("Car2 navigation");
}
}
修改后
public interface CarRun { //行驶 void run(); } public interface CarNavigation { //导航 void navigation(); } public class Car1 implements CarRun { @Override public void run() { System.out.println("Car1 run ...."); } } public class Car2 implements CarRun,CarNavigation { @Override public void run() { System.out.println("Car2 run ..."); } @Override public void navigation() { System.out.println("Car2 navigation"); } }
五、迪米特法则
迪米特法则:如果两个类不比彼此直接通信,那么他们就不应该直接发生作用,它强调的是松耦合,这样的话一个类修改也不会对其他类有太大的影响。
看如下实例有三个类,Car(汽车),Driver(司机),Customer(顾客)和一个测试类,可以看到Customer类中new了一个Car,这就违反了迪米特法则,因为驾驶汽车的活应该交由司机处理,Car类应该是司机内部的类
public class Car { public void run(){ System.out.println("汽车启动..."); } } public class Driver { public void driveCar(Car car){ System.out.println("司机已就绪..."); car.run(); } } public class Customer { public void goHome(Driver driver){ Car car = new Car(); driver.driveCar(car); } } public class test { public static void main(String[] args) { Customer customer = new Customer(); customer.goHome(new Driver()); } }
修改后的类为
public class Customer { public void goHome(Driver driver){ driver.driveCar(); } } public class Driver { Car car = null; public Driver(Car car){ this.car = car; } public void driveCar(){ System.out.println("司机已就绪..."); car.run(); } } public class test { public static void main(String[] args) { Customer customer = new Customer(); Car car = new Car(); customer.goHome(new Driver(car)); } }
这样的话,Customer就不会知道Car实现的细节,全权交由Driver处理。
六、开放-封闭原则
开放-封闭原则:就是类,函数等应该是可以扩展,但是不能修改。这个原则有两个特征,对于扩展是开放的,对于更改是关闭的。但是事实情况是模块不可能完全封闭的,总会有一些变化,但是这时就需要我们去预测可能发生的变化,然后构造抽象来隔离哪些变化,这样的话以后更改起来就可以保持相对稳定,使一个地方的变化对其他地方的影响尽可能的小。