目前字数: 5746,该文章会持续更新。预计目标完结文字大约为5-10万字。
对类来说,即一个类应该只负责一项职责。如果A类负责两个不同的职责,如:职责1,职责2。当职责1需求变更而需要更改A时,可能造成职责2执行错误,所以需要将A这个类的粒度分解为A1,A2。
首先写下以下一段Java代码,非常基础的内容。
package principle.singleresibility;
/**
* 单一职责,小案例1
* 交通小案例
*/
public class SingleResponsibility1 {
public static void main(String[] args) {
Vehicle vehicle = new Vehicle();
vehicle.run("摩托车");
vehicle.run("汽车");
vehicle.run("飞机");
}
}
/**
* 交通工具类
*/
class Vehicle {
public void run(String vehicle) {
System.out.println(vehicle + " 在公路上跑...");
}
}
在运行后,我们会得到以下结果
摩托车 在公路上跑...
汽车 在公路上跑...
飞机 在公路上跑...
这时候我们就会发现有点不对,摩托和汽车在公路上跑就算了,为什么飞机也能在公路上跑。你管地上的也就算了,飞机你也要管。也就是说,在这里违反了单一职责原则。
那么我们就需要有一个解决方案,根据交通工具运行的方式不同,分解成不同的类即可。
package principle.singleresibility;
/**
* 单一职责,小案例1
* 交通小案例
*/
public class SingleResponsibility2 {
public static void main(String[] args) {
// 进行代码测试,通过接口来new对象,分别测试飞机,潜艇,小汽车
VehicleRun car = new RoadVehicle();
car.run("小汽车");
VehicleRun aircraft = new AirVehicle();
aircraft.run("飞机");
VehicleRun submarine = new WaterVehicle();
submarine.run("潜艇");
}
}
/**
* 交通工具接口,都可以run,
* 这样做有效的实现了单一责任,但是他的花销非常大。需要很多个类。且改动很大。即将类分解,同时修改客户端。
*/
interface VehicleRun {
void run(String vehicle);
}
/**
* 路上跑的交通工具类
*/
class RoadVehicle implements VehicleRun {
public void run(String vehicle) {
System.out.println(vehicle + " 公路运行...");
}
}
/**
* 天空运行的交通工具类
*/
class AirVehicle implements VehicleRun {
public void run(String vehicle) {
System.out.println(vehicle + " 天空运行...");
}
}
/**
* 水里运行的交通工具类
*/
class WaterVehicle implements VehicleRun {
public void run(String vehicle) {
System.out.println(vehicle + " 水中运行...");
}
}
但是,这样依然存在问题。这样做有效的实现了单一责任,但是他的花销非常大。需要很多个类。且改动很大。即将类分解,同时修改客户端。也就是说,上述代码依然是可以优化的,我们可以把他全部写在一个类中。
package principle.singleresibility;
public class SingleResponsibility3 {
public static void main(String[] args) {
Vehicle2 vehicle2 = new Vehicle2();
vehicle2.run("汽车");
vehicle2.runAir("飞机");
vehicle2.runWater("轮船");
}
}
/**
* 方式三
* 这种方式并没有对原来的类做大修改,只是增加了方法。
* 他在一定程度上,并没有遵守单一原则,但是在方法拆封上,依然是遵守了单一原则。
*/
class Vehicle2 {
public void run(String vehicle) {
System.out.println(vehicle + " 在公路上运行...");
}
public void runAir(String vehicle) {
System.out.println(vehicle + " 在天上运行...");
}
public void runWater(String vehicle) {
System.out.println(vehicle + " 在水里运行...");
}
}
接口隔离性原则又称 Interface Segregation Principle,客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立于最小的接口上。
类A通过接口Interface1依赖(使用)类B,类c通过接口Interface1依赖(使用)类D,如果接口Interface1对于类A和类c来说不是最小接口那么类B和类D必须去实现他们不需要的方法。
按隔离原则应当这样处理:将接口Interface1拆分为独立的几个接口,类A和类C分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则
请必要看清楚代码和代码内的注释内容。
package principle.segregation;
/**
* 接口隔离性原则, 小案例
*/
public class Segregation1 {
}
/**
* 接口的定义
*/
interface Interface1 {
void operation1();
void operation2();
void operation3();
void operation4();
void operation5();
}
class B implements Interface1 {
@Override
public void operation1() {
System.out.println("B 实现了 operation1");
}
@Override
public void operation2() {
System.out.println("B 实现了 operation2");
}
@Override
public void operation3() {
System.out.println("B 实现了 operation3");
}
@Override
public void operation4() {
System.out.println("B 实现了 operation4");
}
@Override
public void operation5() {
System.out.println("B 实现了 operation5");
}
}
class D implements Interface1 {
@Override
public void operation1() {
System.out.println("D 实现了 operation1");
}
@Override
public void operation2() {
System.out.println("D 实现了 operation2");
}
@Override
public void operation3() {
System.out.println("D 实现了 operation3");
}
@Override
public void operation4() {
System.out.println("D 实现了 operation4");
}
@Override
public void operation5() {
System.out.println("D 实现了 operation5");
}
}
/**
* A 依赖于B,且只使用接口的1,2,3个方法
*/
class A {
public void operation1(Interface1 interface1) {
interface1.operation1();
}
public void operation2(Interface1 interface2) {
interface2.operation2();
}
public void operation3(Interface1 interface3) {
interface3.operation3();
}
}
/**
* C 依赖于D,只用到1, 4, 5个方法
*/
class C {
public void operation1(Interface1 interface1) {
interface1.operation1();
}
public void operation4(Interface1 interface4) {
interface4.operation4();
}
public void operation5(Interface1 interface5) {
interface5.operation5();
}
}
上述代码就会存在一个问题,B和D都实现了Interface1,也就是说五个方法都必须要重写,那么A依赖于B,C依赖于D,且A只需要使用1,2,3方法,C只需要使用1,4,5方法。也就是说,在B中,会有4,5方法用不到,D中会有2,3方法用不到。
解决方法,将接口Interface1拆分为几个独立的接口,类A和类C分别与他们需要的接口建立依赖关系,也就是采用接口隔离原则。接口Interface1中出现的情况,根据实际情况拆分为三个接口。
上述拆分也很好理解,一共有五个方法,分别是 1 2 3 4 5,A使用到了1 2 3, C使用到了 1 4 5,把公共的1单独拆出来一份,然后分别拆不同的内容,也就是拆出来一个2 3,在拆出来一个4 5
package principle.segregation.improve;
/**
* 接口隔离性原则案例改进
*/
public class SegregationImprove {
public static void main(String[] args) {
A a = new A();
a.operation1(new B());
a.operation2(new B());
a.operation3(new B());
C c = new C();
c.operation1(new D());
c.operation4(new D());
c.operation5(new D());
}
}
interface Interface1 {
void operation1();
}
interface Interface2 {
void operation2();
void operation3();
}
interface Interface3 {
void operation4();
void operation5();
}
class B implements Interface1, Interface2 {
@Override
public void operation1() {
System.out.println("B 实现了 operation1");
}
@Override
public void operation2() {
System.out.println("B 实现了 operation2");
}
@Override
public void operation3() {
System.out.println("B 实现了 operation3");
}
}
class D implements Interface1, Interface3 {
@Override
public void operation1() {
System.out.println("D 实现了 operation1");
}
@Override
public void operation4() {
System.out.println("D 实现了 operation4");
}
@Override
public void operation5() {
System.out.println("D 实现了 operation5");
}
}
/**
* 创建A和C分别依赖于B和D实现各自对应的方法
* A: 1, 2, 3
* C: 1, 4, 5
*/
class A {
public void operation1(Interface1 interface1) {
interface1.operation1();
}
public void operation2(Interface2 interface2) {
interface2.operation2();
}
public void operation3(Interface2 interface2) {
interface2.operation3();
}
}
class C {
public void operation1(Interface1 interface1) {
interface1.operation1();
}
public void operation4(Interface3 interface3) {
interface3.operation4();
}
public void operation5(Interface3 interface3) {
interface3.operation5();
}
}