浅谈利用多态,继承和接口来封装代码,提高Java代码的可扩展性

一个人做项目的时候是最爽的, 因为可以肆无忌惮的按照自己的想法去"策马奔腾", 因为往往会优先选择实现成本最低且个人偏好的方式去实现, 简单的说就是, 怎么爽就怎么做.这样的情况,项目在实现时候如果只考虑方便快捷而忽略了关键的需求分析和架构设计, 虽然可能很快就能做出来,但质量不高. 并且一个具有生命期的项目, 它的代码是应该具有相当规范的.这个项目应当是, 即使其他工程师加入项目组中也能较快较容易的理解这个项目的架构和代码, 并且添加或修改功能的成本较低. 想象下, 要是每次都将重构代码, 推倒重来, 这是多么可怕的事儿呢?!

那么回归正题, 相信很多人都朋友一些功能是调用别人的接口, 比如发短信, 比如我们常见的各种api 等等, 我们只需要按照约定的规范和方式就能很方便的调用接口,而不必考虑它们是如何实现的, 这是多么幸福的事呢. 

1,  多态

多态是代码运行时的行为, 核心就是类型转换. 比如父类的引用指向子类的对象 (向上转换).

class People{
		public void run(){
			System.out.println("people are running.");
		}
	}
	
	class Man extends People{
		public void run(){
			System.out.println("man is running.");
		}
		public void jump(){
			System.out.println("women is jumping.");
		}
	}
	
	
	public void MainTest(){
		Man man = new Man();
		People pe = man;
		pe.run();		//向上类型转换, 父类引用指向子类
		
		//向下类型转换, 强制转换
		People pA = new Man();
		Man mA = (Man)pA;
		mA.run();
		mA.jump();
	}

打印结果:

man is running.

man is running.

women is jumping.


上面的向上类型转换中, 父类People指向了子类Man,从而具有了Man的行为.  就是说,一旦父类指向不同的子类, 就可以具有不同的行为. 这就是多态.

另外, 如果父类对象pe调用man中jump()方法, 由于这个方法在People中并没有定义, 就会报错.

多态是Java中非常重要的特性, 它使得(针对向上类型转换而言)父类不再局限于自身的行为, 可以通过子类扩充更多行为,更加的灵活.


2,继承

本质而言,Java只有单继承, 即每个子类只能有父类. 继承的好处是, 子类一旦继承父类, 除了具备父类的属性行为, 还能自定义添加扩充更多有用的属性行为上去. 比如上面的Man类继承了父类People,除了可以拥有run()这个方法还能自己扩充jump()方法, 使子类Man实现了扩展. 当然, 上面的小例子中, Man和People都拥有run()方法, 这里用到了"覆盖", 这是子类对父类同名的方法的覆盖和重写, 要求方法名和参数类型,个数必须一致. 另外和"覆盖" 相随的还有常见的"重载". 重载是子类对父类的方法必须同名而参数类型或者参数个数不一致. 这里并不细说,单独知识点可以网上很多文章可以了解.

还有个小点,子类在构造方法中可以先通过super调用父类的构造方法再自定义自己的行为.

继承的属性, 让子类拥有了父类的全部属性行为, 还能扩展地定义更多的东西, 这使得子类能够更饱满更有生产实现的能力.


3,接口

也许会有人说,单继承太局限了吧? 我要多继承怎么办? 于是,接口来了.

接口是更加灵活的手段, 它类似抽象类一样定义了一种规范, 至于怎么实现就是实现这个接口的类本身的事情, 接口咱不管这个.因此, 接口中只定义了方法名,参数类型和个数以及返回值, 并没有实现的方法体(这就像抽象类中的抽象方法, 只定义不实现, 其实接口中定义的方法也是抽象方法). 比如:

public interface person{
		public void swim();		//在接口person定义swim()方法
	}
	
	class Children extends People implements person{
		
		public Children(String name){
			super();
			climb(name);
		}
		
		public void climb(String name){
			System.out.println(name +" is climbing.");
		}
		
		public void swim(){	//此处实现了person接口中的swim()方法
			System.out.println("children are swimming.");
		}
	}
	
	public void iMainTest(){
		Children children = new Children("Tom");
		children.swim();
	}
	
	class People{
		public void run(){
			System.out.println("people are running.");
		}
	}

打印结果:

people are running.

Tom is climbing.

children are swimming.


在上面的小例子中, 子类Children通过继承父类People有了People的run()方法, 并在构造方法中调用了run(), 同时还实现了person这个接口, 使自己又有了swim()方法.这样子类Children一下子被扩展起来, 不但学会了"跑步", 还会"游泳"和"爬山" (定义了Tom这个人的爬山行为). 接口的灵活性 -- 只定义, 不实现. 使得同样的接口在不同的类中可以有不同的实现, 而由于系统功能的多样性和复杂度的特点, 要求功能在实现的时候不能被固化写死了(比如swim()这个方法, 在A类是"蛙泳", 在B类是"蝶泳" ,在C类却是"自由式", 所以同样是游泳"swim"这个运动, 在不同类却需要有不同的行为), 可见接口对功能的扩展实现非常重要.


4,总结

以上,浅谈多态,继承和接口 并没有分开细讲是因为每个点其实都涉及更多小点才能使知识点更系统, 一篇文章就固然不够了, 本文尽量用最简单的方式方法归类总结这三个重要的特点, 关键是先明白怎么回事, 一旦入门了,至于更多来龙去脉的细节就能更容易理解一些.


下面综合多态,继承和接口,举个栗子

/**
	 *回调接口
	 */
	public interface tCallBack{
		public void callback(String name);
	}
	
	
	/**
	 * fly功能接口
	 */
	public interface flyListener{
		public void fly(String name);
	}
	
	
	/**
	 * 父类
	 */
	class Father implements flyListener {
		String name;
		
		public Father(){
			super();
		}
		
		public Father(String name){
			super();
			this.name = name;
			fly(this.name);
		}
		
		public void fly(String name){
			Sing(name, new tCallBack() {
				public void callback(String str){
					//方法实现
					System.err.println(str + " is singing.");
				}
			});
		}
	}
	
	/**
	 * 区别同名方法
	 * @param songName
	 * @param callback
	 */
	public static void Sing(String songName,tCallBack callback){
		
		callback.callback(songName);
		
	}
	
	public static void Sing(String songName){
		System.out.println("wow, the song's name is " + songName);
	}
	
	
	class Daughter extends Father{
		public Daughter(String name){
			super(name);
		}
		
		@Override
		public void fly(String name){
			System.out.println(name + " is now flying.");
		}
				
	}
	
	
	/**
	 * 子类
	 * @author Mr.Et
	 *
	 */
	class Son extends Father{
		public Son(){
			super("Amy");
			fly("kelly");
			Sing("fly in the sky.");
			Daughter dg = new Daughter("John");
			Father ft = dg;
			ft.fly(ft.name);
		}
		
		@Override
		public void fly(String name){ 
			System.out.println(name + " is flying.");
		}
		
	}

运行子类Son, 打印结果:

Amy is singing.

kelly is flying.

wow, the song's name is fly in the sky. 

John is now singing.

上面如果要扩展son的功能, 可以利用接口重新去实现方法, 可以自定义静态方法, 也可以在父类中定义赋予更多可靠的方法, 然后在son中使用. 当多态,继承和接口与结合起来,就发现其实这样的扩展性是挺大, 起码不再将一大堆明明可以隐藏的代码放在同一个地方, 而且改动的时候也不必将father,daughter或者son全部都改一遍.

谈到代码的可扩展性, 这在项目在设计和实现时必不可少的一道菜. 都说"高内聚,低耦合". 我们在实现功能的时候, 要尽量考虑减少功能与功能之间, 类与类之间, 方法与方法之间 的关系, 怎么使得它们在改动的时候能尽量少牵涉其他的类方法, 避免"牵一发而动全身".这就要求功能在实现的时候就考虑了扩展性和可维护.  比如把类中用到的方法全部放在类本身, 自己用不让别人用,而当别人用的时候又去重新写大量的代码, 这就造成了系统代码的冗余和重复, 而且在改动某个变量时几乎是整个类本身都要改动, 就真是吃力不讨好. 于是写代码时就要多利用多态, 继承和接口的这些重要特性来降低耦合(还有其他方式,以后再写), 将方法功能尽量封装好, 只对外暴露接口. 这是最好的.


  • 3
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值