1、依赖倒置原则的理解
所谓依赖倒置原则(Dependence Inversion Principle )就是要依赖于抽象,不要依赖于具体。简单的说就是对抽象进行编程,不要对实现进行编程,这样就降低了客户与实现模块间的耦合。
面向过程的开发,上层调用下层,上层依赖于下层,当下层剧烈变化时,上层也要跟着变化,这就会导致模块的复用性降低而且大大提高了开发的成本。
面向对象的开发很好的解决了这个问题,一般的情况下抽象的变化概率很小,让用户程序依赖于抽象,实现的细节也依赖于抽象。即使实现细节不断变化,只要抽象不变,客户程序就不需要变化。这大大降低了客户程序域实现细节的耦合度。
2、问题优化UML图与编程实现
(1)一个汽车电子公司现在规划开发一个自动驾驶系统,只要汽车上安装上这个系统,就可以实现无人驾驶,该系统可以在福特车系列和本田车系列上使用。
public class AutoSystem {
public enum CarType{ Ford,Honda}
private HondaCar hondcar = new HondaCar();
private FordCar fordcar = new FordCar();
private CarType type;
public AutoSystem(CarType carType)
{
this.type =carType;
}
public void RunCar()
{
if (this.type == CarType.Honda)
{
hondcar.Run();
}
else if(this.type == CarType.Ford)
{
fordcar.Run();
}
}
public void StopCar()
{
if(this.type == CarType.Honda)
{
hondcar.Stop();
}
else if (this.type == CarType.Ford)
{
fordcar.Stop();
}
}
public void TurnCar()
{
if(this.type == CarType.Honda)
{
hondcar.Turn();
}
else if (this.type == CarType.Ford)
{
fordcar.Turn();
}
}
public static void main(String[] args) {
AutoSystem autoSystem = new AutoSystem(CarType.Honda);
autoSystem.RunCar();
autoSystem.StopCar();
autoSystem.TurnCar();
AutoSystem autoSystem1 = new AutoSystem(CarType.Ford);
autoSystem1.RunCar();
autoSystem1.StopCar();
autoSystem1.TurnCar();
}
}
public class FordCar {
public void Run() { System.out.println(“福特车启动”);}
public void Turn() { System.out.println(“福特车拐弯”);}
public void Stop() { System.out.println(“福特车停止”);}
}
public class HondaCar {
public void Run() { System.out.println(“本田车启动”);}
public void Turn() { System.out.println(“本田车拐弯”);}
public void Stop() { System.out.println(“本田车停止”);}
}
(2)如果现在公司业务规模扩大了,该自动驾驶系统还要把吉普车也兼容了。
如何修改这个设计?
修改如下:
public class AutoSystem {
private Cars car;
public AutoSystem(Cars car)
{
this.car =car;
}
public void RunCar()
{
this.car.Run()
}
public void StopCar()
{
this.car.Stop();
}
public void TurnCar()
{
this.car.Turn();
}
public static void main(String[] args) {
AutoSystem autoSystem = new AutoSystem(CarType.Honda);
autoSystem.RunCar();
autoSystem.StopCar();
autoSystem.TurnCar();
AutoSystem autoSystem1 = new AutoSystem(CarType.Ford);
autoSystem1.RunCar();
autoSystem1.StopCar();
autoSystem1.TurnCar();
AutoSystem autoSystem2 = new AutoSystem(CarType.Jeep);
autoSystem2.RunCar();
autoSystem2.StopCar();
autoSystem2.TurnCar();
}
}
public interface Cars {
void Run();
void Stop();
void Turn();
}
public class HondaCar implements Cars {
public void Run() { System.out.println(“本田车启动”);}
public void Turn() { System.out.println(“本田车拐弯”);}
public void Stop() { System.out.println(“本田车停止”);}
}
public class FordCar implements Cars {
public void Run() { System.out.println(“福特车启动”);}
public void Turn() { System.out.println(“福特车拐弯”);}
public void Stop() { System.out.println(“福特车停止”);}
}
public class Jeep implements Cars {
public void Run() { System.out.println(“吉普车启动”);}
public void Turn() { System.out.println(“吉普车拐弯”);}
public void Stop() { System.out.println(“吉普车停止”);}
}
3、接口隔离原则的实验
在使用接口时要注意控制接口的粒度,接口定义的粒度不能太细,也不能太粗。 接口粒度太细,系统中就会出现接口泛滥,接口和实现类急剧膨胀,反而不易维护;接口粒度太粗,就会违背ISP,系统的灵活性就会降低,不易维护和扩展。
假设有个客户提出了软件系统的需求:
- 用户可以使用第三方QQ,微信,微博登录到系统。
2.系统中包括人员管理人员管理。
3.访问第三方的API获取一些数据。
4.等过了几天客户说 在给我加上支付宝登录
5.时间在推移,一天客户说再给我加个百度登录
public interface IObject
{
void Connection(string connectionString);
SqlDataReader ExcuteSql(string sql);
string LoginWithQQ(string token);
string LoginWithWeibo(string token);
string LoginWithWeiXin(string token);
string GetDataFromAPI(string url, string token);
string LoginWithAlipay(string token);
string LoginWithTwitter(string token);
string LoginWithFaceBook(string token);
string LoginWithRenRen(string token);
string LoginWithBaidu(string token);
string LoginWithDropbox(string token);
string LoginWithGithub(string token);
//这里省略10000字
stringLoginWithLinkedin(string token);
}
重构:经过分析
第一步先根据功能来划分将IObject接口拆分成三个“小”接口:
1.数据库操作相关的抽取到一个接口中(IDatabaseProvider)。
2.第三方API调用相关的方法抽取到一个接口中(IThirdpartyAPIProvider)。
3.第三方登陆相关的方法抽取到一个接口中(IThirdpartyAuthenticationProvider)。
第二步 我们可以将第三方登录的接口中的LogigWithxxx方法提到一个单独的接口中,其他具体站点的接口再继承这个接口
重构后如下: