面向接口编程思想与实现可维护的代码 (一)
某日
小A打开手机,王者荣耀启动,连赢十把之后,辣鸡游戏真没意思,卸载。
扭头看见没怎么翻过的Java从入门到放弃,心想自己写个小游戏岂不美哉?说着拿起键盘噼里啪啦一阵敲。
`
public class Main1 {
public static void main(String[] args) {
// 用户选择英雄
String name = Main1.getPlayerInput();
// 英雄放技能
switch (name) {
case "亚瑟":
Arthur arthur = new Arthur();
arthur.skill1();
break;
case "露娜":
Luna luna = new Luna();
luna.skill1();
break;
case "孙尚香":
SunShangXiang xiang = new SunShangXiang();
xiang.skill1();
break;
}
}
private static String getPlayerInput() {
System.out.println("请选择英雄:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
return name;
}
}
`
很自然的这么写,写了一连串他感觉这写的真是够啰嗦,如果英雄放大招岂不是又要逐个调用skill3()?三四个英雄还好,以后扩增到300个英雄……
小A在键盘上飞舞的手停顿了一下,心想虽然我的手速够快,可是这么写下去手岂不是要断?
突然想起昨天刚看的面向接口编程思想 …… o_★ 有了! 于是他写了个接口:
`
public interface SkillImpl {
void skill1();
void skill2();
void skill3();
}
`
并用Arthur实现了这个接口:
`
public class Arthur implements SkillImpl{
public void skill1() {
System.out.println("【亚瑟】释放了1技能:誓约之盾");
}
public void skill2() {
System.out.println("【亚瑟】释放了2技能:回旋打击");
}
public void skill3() {
System.out.println("【亚瑟】释放了大招:圣剑裁决");
}
}
`
然后随手把main方法里的代码改了:
`
public class Main2 {
public static void main(String[] args) throws Exception {
// 用户选择英雄
String name = Main2.getPlayerInput();
SkillImpl skillImpl;
switch (name) {
case "亚瑟":
skillImpl = new Arthur();
break;
case "露娜":
skillImpl = new Luna();
break;
case "孙尚香":
skillImpl = new SunShangXiang();
break;
default:
throw new Exception();
}
skillImpl.skill1();
}
private static String getPlayerInput() {
System.out.println("请选择英雄:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
return name;
}
}
`
改完后小A看着自己的代码不自觉地点了点头,这样就把方法的调用统一起来了,全部集中在一个接口的方法调用上面。
上一个版本的switch里除了有对象的生成还有业务逻辑,非常不单纯, 现在switch逻辑很简单,就只做一件事 ———— 给SkillImpl实例化。
面向对象很多时候就是在做两件事:一是实例化对象,二是调用方法完成业务逻辑。现在调用方法完成业务逻辑已经OK了,
但是单纯的 interface 可以统一方法的调用,却不能统一对象的实例化。
如果又新增一个英雄还是要改业务主体的代码,并没有完全解决问题……
小A陷入了沉思……如果把它提取成一个方法,再进行方法的调用,下一次就不用改main方法里的代码了。emm……可行。
可是下次新增英雄还不是要改所调用的方法里的代码?!
又一想需求是会变更的,代码中总是会存在不稳定,隔离这些不稳定,让主要逻辑方法里main 的代码是稳定的就可以了。
想完,小A加了一个生产英雄的工厂类,把main方法里的代码挪了进去:
`
public class HeroFactory {
public static SkillImpl getHero(String name) throws Exception {
SkillImpl skillImpl;
switch (name) {
case "亚瑟":
skillImpl = new Arthur();
break;
case "露娜":
skillImpl = new Luna();
break;
case "孙尚香":
skillImpl = new SunShangXiang();
break;
default:
throw new Exception();
}
return skillImpl;
}
}
`
现在main方法里看着清晰多了,我再放个技能,再来个大招,轻轻松松的:
`
public class Main3 {
public static void main(String[] args) throws Exception {
// 用户选择英雄
String name = Main3.getPlayerInput();
SkillImpl skillImpl = HeroFactory.getHero(name);
skillImpl.skill1();
skillImpl.skill2();
skillImpl.skill3();
}
private static String getPlayerInput() {
System.out.println("请选择英雄:");
Scanner scanner = new Scanner(System.in);
String name = scanner.nextLine();
return name;
}
}
`
小A不住点头,露出了欣慰的笑容,我的手算是保住了,果然以后还是要多看看书。
> Java追求的是代码的稳定性和可维护性:
> Java提倡面向抽象编程,而不要面向具体去编程。面向抽象编程表面上的目的是不要依赖一个具体的类,而是要去依赖抽象,它真正的目的是为了实现可维护的代码。
> 对于生命周期比较长的项目,我们需要长期维护、迭代、更新,一些设计思想和方法论就非常非常重要。如果没有方法论在里面,以后需要更改某些属性,就可能引发非常严重的错误。
面向接口编程思想:
面向接口编程不与面向对象编程同级,而是附属于面向对象编程思想,是面向对象编程思想的精髓之一。这也是设计的一大原则:程序依赖接口,不依赖具体实现。
一个接口就是我们要调用的一系列方法的集合,有对象将会响应这些方法调用。一个实现就是为接口存放代码和逻辑的地方。本质上讲,这个原则倡导的是,当我们写一个函数或一个方法时,我们应该引用相应的接口,而不是具体的实现类。这是一个非常强大的编程思想,我们写出越多可复用的代码,用于维护它们的时间就会越少,接口提供了非常优秀的抽象归纳,让我们的开发工作变得容易很多。虽然并不是什么时候都可以面向接口编程的,但遵循这种原则会让你更容易的写出可复用的更优雅的代码。【引用】链接:http://www.aqee.net/post/program-to-an-interface-fool.html
定义
在系统分析和架构中,分清层次和依赖关系,每个层次不是直接向其上层提供服务(即不是直接实例化在上层中),
而是通过定义一组接口,仅向上层暴露其接口功能,上层对于下层仅仅是接口依赖,而不依赖具体类
本质
1.接口是一组规则的集合,它规定了实现本接口的类或者接口必须拥有的一组规则。
2.接口是在一定粒度视图上同类事物的抽象表示,实现了多态性。
优点
1.结构清晰,使用方便。
2.设计合理的接口,有利于程序的规范化,可并行进行开发,从而提高效率。
3.提高系统的灵活性,当下层需要改变时,只要接口及接口功能不变,则上层不用做任何修改。
4.实现了程序的可插拔性,对于不同的需求切换不同的实现,降低了耦合度,随着系统的复杂性的提高优势会愈加明显(低耦合、易扩展、易维护)。
5.允许多重实现,弥补了继承的缺陷。
缺点
1.增加了设计复杂度,不适用于简单的系统。
2.可能会降低代码的可复用性。
3.可能会降低程序的执行效率。
【引用】链接:https://www.cnblogs.com/aimaogoudexiaohao/p/12050928.html
接口泛指实体把自己提供给外界的一种抽象化物,用以由内部操作分离出外部「沟通方法」,使其能被内部修改而不影响外界其他实体与其交互的方式。
在一个面向对象的系统中,系统的各种功能是由许许多多的不同对象协作完成的。在这种情况下,各个对象内部是如何实现自己的,对系统设计人员来讲就不那么重要了(通俗的说,就是你会调接口就完事了,接口背后具体怎么实现的你不用管);而各个对象之间的协作关系(接口)则成为系统设计的关键。小到不同类之间的通信,大到各模块之间的交互,在系统设计之初都是要着重考虑的,这也是系统设计的主要工作内容。面向接口编程就是指按照这种思想来编程。(btw,所以那些设计接口的程序猿更赚钱啊,哦,应该喊他们架构师)。
接口的作用 1. 制定标准 2. 提供可扩展性
【引用】链接:https://zhuanlan.zhihu.com/p/119152601
接口这个概念在实际生活中最常见的例子就是:插座!
我们只需要事先定义好插座的接口标准,各大插座厂商只要按这个接口标准生产,管你什么牌子、内部什么电路结构,这些均和用户无关,用户拿来就可以用;而且即使插座坏了,只要换一个符合接口标准的新插座,一切照样工作!
同理,实际代码设计也是这样!我们在设计一个软件的代码架构时,我们都希望事先约定好各个功能的接口(即:约定好接口签名和方法),实际开发时我们只需要实现这个接口就能完成具体的功能!后续即使项目变化、功能升级,程序员只需要按照接口约定重新实现一下,就可以达到系统升级和扩展的目的!
【引用】链接:http://www.imooc.com/article/301555