沉寂了一个月的时间,仔细学习了下设计模式,从本篇博文开始陆续更新设计模式系列的文章,我给它起了个有意思的名字叫做:“围观”设计模式,当然围观是加引号的,我写博文分享的目的一方面是将自己学到的一些心得体会分享给大家,另一方面是博文与实际的案例结合,达到可以用于实际项目中的目的。希望看到博文的朋友多多提出宝贵的建议与批评,我会虚心的接受。
单一功能原则(Single responsibility principle)规定每个类都应该有一个单一的功能,并且该功能应该由这个类完全封装起来。所有它的(这个类的)服务都应该严密的和该功能平行(功能平行,意味着没有依赖)。——维基百科
我们这里定义了这样的一个接口,包括setCarName,setCarColor,startUp,run和stop方法,那么这里应该很明显,所有的事情都要交给Car的实现类去完成,其中setCarName,setCarColor可以认为是完成了属性设置的任务,而后面的三个startUp、run、stop则完成了车的具体动作。从这里可以看出这个接口提供的方法存在职责不单一的问题,当然话说回来,setCarName和setCarColor如果放在一个接口中,那就职责单一了吗?一个设置名称,一个是设置颜色,也不是完全的单一嘛,我在这里的看法是不要斤斤计较,过分的划分功能,会导致设计的复杂化,加大工作量,所以在这里我觉得职责在划分的时候,需要进行一个抽象的过程,将完成的功能相近的划分到一起我觉得就可以了。
package cn.design.pattern2016032001SingleResponsibility; public interface Car { /** 设置名称 */ public void setCarName(String carName); /** 设置颜色*/ public void setCarColor(String carColoe); /** 启动*/ public void startUp(); /** 行驶*/ public void run(); /** 停止*/ public void stop(); }
package cn.design.pattern2016032001SingleResponsibility; public class CarImpl implements Car { @Override public void setCarName(String carName) { System.out.println("名称:" + carName); } @Override public void setCarColor(String carColoe) { System.out.println("颜色:" + carColoe); } @Override public void startUp() { System.out.println("启动"); } @Override public void run() { System.out.println("行驶"); } @Override public void stop() { System.out.println("停止"); } }
package cn.design.pattern2016032001SingleResponsibility; public class MainTest { public static void main(String[] args) { Car car = new CarImpl(); car.setCarName("HongQi"); car.setCarColor("Black"); car.startUp(); car.run(); car.stop(); } }
那么我们应该怎么设计这个接口呢?
参考了《设计模式之禅》中的例子,将不同职责的操作分开到不同的接口中去。
package cn.design.pattern2016032002SingleResponsibility; public interface Car { /** 设置名称 */ public void setCarName(String carName); /** 设置颜色*/ public void setCarColor(String carColoe); }
package cn.design.pattern2016032002SingleResponsibility; public interface CarAction { /** 启动*/ public void startUp(); /** 行驶*/ public void run(); /** 停止*/ public void stop(); }
package cn.design.pattern2016032002SingleResponsibility; public interface CarOperate extends Car, CarAction{ }
package cn.design.pattern2016032002SingleResponsibility; public class CarImpl implements CarOperate{ @Override public void setCarName(String carName) { System.out.println("名称:" + carName); } @Override public void setCarColor(String carColoe) { System.out.println("颜色:" + carColoe); } @Override public void startUp() { System.out.println("启动"); } @Override public void run() { System.out.println("行驶"); } @Override public void stop() { System.out.println("停止"); } }
package cn.design.pattern2016032002SingleResponsibility; public class MainTest { public static void main(String[] args) { CarOperate car = new CarImpl(); Car carSet = (Car) car; carSet.setCarName("HongQI"); carSet.setCarColor("Black"); CarAction carAction = (CarAction)car; carAction.startUp(); carAction.run(); carAction.stop(); } }这些代码比较简单,我这里就不再过多的说明了。
我对这个问题有自己的看法,看下类图
这里会发生耦合,理论上应该尽量避免的,但是我觉得这样设计的话更能体现出单一职责原则。不过应该说尽量避免耦合才好,可能我的这种想法并不是推荐的方法。读者可以进行参考。
package cn.design.pattern2016032003SingleResponsibility; public interface Car { /** 设置名称 */ public void setCarName(String carName); /** 名称 */ public String getCarName(); /** 设置颜色*/ public void setCarColor(String carColoe); /** 颜色 */ public String getCarColor(); }
public interface CarAction { /** 启动*/ public void startUp(); /** 行驶*/ public void run(); /** 停止*/ public void stop(); }
package cn.design.pattern2016032003SingleResponsibility; public class CarImpl implements Car{ private String carName; private String carColor; @Override public void setCarName(String carName) { this.carName = carName; System.out.println("名称:" + carName); } @Override public void setCarColor(String carColoe) { this.carColor = carColoe; System.out.println("颜色:" + carColoe); } @Override public String getCarName() { return this.carName; } @Override public String getCarColor() { return this.carColor; } }
package cn.design.pattern2016032003SingleResponsibility; public class CarActionImpl implements CarAction{ private Car car; public CarActionImpl(Car car){ this.car = car; } @Override public void startUp() { System.out.println("启动>>" + car.getCarName()); } @Override public void run() { System.out.println("行驶"); } @Override public void stop() { System.out.println("停止>>" + car.getCarName()); } }
package cn.design.pattern2016032003SingleResponsibility; public class CarOperate { private Car car ; private CarAction carAction ; public CarOperate(Car car, CarAction carAction){ this.car = car; this.carAction = carAction; } public Car getCar() { return car; } public CarAction getCarAction() { return carAction; } }
package cn.design.pattern2016032003SingleResponsibility; public class MainTest { public static void main(String[] args) { Car car = new CarImpl(); CarAction carAction = new CarActionImpl(car); CarOperate carOper = new CarOperate(car, carAction); /** * 如果在Action中需要得到Car中的属性可以通过构造函数进行设置 */ carOper.getCar().setCarColor("Black"); carOper.getCar().setCarName("HongQI"); carOper.getCarAction().startUp(); carOper.getCarAction().stop(); } }
1. 降低了单个类的复杂性,尽量保证一个类中操作的类型一致
2. 可读性较好,因为单一职责的原因,对某种职责的操作可以去具体的类中查看。
单一职责原则,理论上我们要进行遵循的,但是往往实践中并不一定完全按照他的思路去设计,我的看法还是,尽量在完成业务需要的情况下,考虑按照单一职责原则对接口和类进行设计,类的设计过程中,不要过度的划分,适可而止就好。
源码已经上传至GitHub:下载设计模式代码