第二十条:与抽象类相比,优先选择接口

news/2024/7/7 19:56:27 标签: java, 开发语言

要定义多种实现的类型:JAVA有两种机制:接口和抽象类。这两种机制都支持为某些实例方法提供实现,但二者有个重要的区别:要实现由抽象类定义的类型,这个类必须是抽象类的子类。因为Java只允许单继承,对抽象类的这种限制严重制约了将其用于类型的定义。而接口就宽松很多,只要定义了所有必须的方法,任何类都可以实现。

在正式介绍之前普及两个知识点:缺省方法和抽象方法。

这两个方法是相反的用途:缺省是为了避免子类重写其方法。抽象方法是为了让子类重写方法。

缺省方法(default)案例:

public interface SoyaMilk2 {



	default void select() {
		System.out.println("选择");
	}
}

子类:

public class RedInter implements SoyaMilk2 {

}

抽象方法案例:

public interface SoyaMilk2 {
	abstract void addCondiments();

}

子类:

接口优先于抽象类优点:

1.很容易改造现有的类使其实现一个新的接口。

2.接口是定义minxin(混合类型)的理想选择。

3.接口允许构建非层次结构的类型框架。

案例:

public interface Singer {
    //唱歌
    AudioClip sing(Song s);
}

public interface SongWriter {
    //作歌
    Song compose(boolean hit);
}
public intreface SingerSongWriter extends Singer, SongWriter {
    //弹奏
    AudioClip strum();
    //激情表演
    void actSensitive();
}

抽象类:

Singer.java
public abstract class Singer {
    //唱歌
    public abstract AudioClip sing(Song s);
}

SongWriter.java
public abstract class SongWriter {
    //作歌
    public abstract Song compose(boolean hit);
}

SingerSongWriter.java
//在设计的时候感觉很不好设计。因为继承只能继承自一个类,那势必其他的方法需要重新声明
public abstract class SingerSongWriter extends SongWriter {
    //唱歌
    public abstract AudioClip sing(Song s);

    //弹奏
    public abstract AudioClip strum();
    //激情表演
    public abstract void actSensitive();
}

在引入抽象骨架概念之前,先分别看下接口和抽象类的案例实现:

(1)接口案例:

定义接口:

public interface IPeple {

	void drink();
	void eat();
	void ethnicGroup();

}

分别定义子类:

public class AsiaPeple implements IPeple {
	@Override
	public void drink() {
		System.out.println("人都会喝水");
	}

	@Override
	public void eat() {
		System.out.println("人都会吃饭");
	}

	@Override
	public void ethnicGroup() {
		System.out.println("亚洲人大多数是黄种人");
	}
}
public class AmericanPeple implements IPeple {
	@Override
	public void drink() {
		System.out.println("人都会喝水");
	}

	@Override
	public void eat() {
		System.out.println("人都会吃饭");
	}

	@Override
	public void ethnicGroup() {
		System.out.println("美洲人大多数是白种人");
	}
}

问题:

drink和eat方法代码重复性很高,需要改造。

(2)抽象类案例:

定义抽象类:

public abstract class AbsPeple {
	void drink(){
		System.out.println("人都会喝水");
	}
	void eat() {
		System.out.println("人都会吃饭");
	}
	abstract void ethnicGroup();
}

分别定义子类:

public class AmericanPeple extends AbsPeple {

	@Override
	void ethnicGroup() {
		System.out.println("美洲人大多数是白种人");
	}
}

public class AsiaPeple extends AbsPeple{
	@Override
	void ethnicGroup() {
		System.out.println("亚洲人大多数是黄种人");
	}

	public static void main(String[] args) {
		AsiaPeple asiaPeple = new AsiaPeple();
		asiaPeple.eat();
		asiaPeple.drink();
		asiaPeple.ethnicGroup();
		AmericanPeple americanPeple = new AmericanPeple();
		americanPeple.eat();
		americanPeple.drink();
		americanPeple.ethnicGroup();
		System.out.println(asiaPeple);
		System.out.println(americanPeple);
	}
}

结果打印:

人都会吃饭
人都会喝水
亚洲人大多数是黄种人
人都会吃饭
人都会喝水
美洲人大多数是白种人
com.example.exceldemo.abstact.entity.AsiaPeple@7699a589
com.example.exceldemo.abstact.entity.AmericanPeple@58372a00

缺点:一旦一个类继承了抽象类AbsPeple,那么它就无法继承其它类。而且我们也知道,继承实现有很多问题,太多的继承会造成代码耦合性问题,不利于以后的维护和升级。抽象骨架氤氲而生。

(3)抽象骨架概念:(抽象类继承接口,不要求重写接口中缺省、抽象方法)

可以将接口和抽象类的优点结合到一起。其中,接口用来定义类型,可能还会提供一些默认的方法,而骨架实现类负责在基本接口方法之上实现其余的非基本接口方法(ethnicGroup()方法)。扩展骨架实现类可以省去实现接口需要的大部分工作。这就是模板方法【设计模式】(中级面试很多面试官喜欢问设计模式)

定义抽象骨架:

public abstract class AbsPeple implements IPeple{
	@Override
	public void drink() {
		System.out.println("人都要喝水");
	}

	@Override
	public void eat() {
		System.out.println("人都要吃饭");
	}
}

定义私有类及成员(AsiaPeple重写接口统一方法,成员变量获取单独的重写方法):

public class AsiaPeple implements IPeple {

	private AsiaPepleIpml asiaPepleIpml = new AsiaPepleIpml();
	private static class AsiaPepleIpml extends AbsPeple {

		@Override
		public void ethnicGroup() {
			System.out.println("亚洲人大多数都是黄种人");
		}
	}





	public static void main(String[] args) {
		AsiaPeple asiaPeple = new AsiaPeple();
		asiaPeple.eat();
		asiaPeple.drink();
		asiaPeple.asiaPepleIpml.ethnicGroup();

	}

	@Override
	public void drink() {
		asiaPepleIpml.drink();
	}

	@Override
	public void eat() {
		asiaPepleIpml.eat();
	}

	@Override
	public void ethnicGroup() {
		throw new UnsupportedOperationException("不重新方法");
	}
}

打印结果:

人都要吃饭
人都要喝水
亚洲人大多数都是黄种人

Process finished with exit code 0

AsiaPeple类 可以实现多个接口和定义多个抽象骨架实现类,使得AsiaPeple类非常非常灵活多变。

骨架实现类的美妙在于,他们提供了抽象类的所有实现帮助,又不存在将抽象类用于类型定义时所面临的严格限制。接口本身存在的任何默认方法,对于这个类还是有帮助的。此外,仍然可以利用骨架实现来帮助实现者完成任务:实现该接口的类可以引入一个私有的、扩展了骨架实现类的内部类,并包含一个这个内部类实例,然后将对接口方法的调用转发给这个实例。这种技术被称为模拟多重继承。

因为骨架实现是为了继承而设计的,好的文档在骨架实现中是绝对必要的,无论它是由接口上的默认方法组成还是单独的抽象类。

总而言之,要定义支持实现的类型,接口通常是最佳选择如果导出一个不是很简单的接口,请务必考虑配合提供一个骨架实现。在可能的情况下,应该通过接口上的默认方法来提供骨架的实现,以便该接口的所有实现者都可以使用。即便如此,接口上的限制常会使得抽象类形式成为骨架实现的不二之选。

所有文章无条件开放,顺手点个赞不为过吧!

                                                               


http://www.niftyadmin.cn/n/5535058.html

相关文章

​香橙派AIpro测评:usb鱼眼摄像头的Camera图像获取

一、前言 近期收到了一块受到业界人士关注的开发板"香橙派AIpro",因为这块板子具有极高的性价比,同时还可以兼容ubuntu、安卓等多种操作系统,今天博主便要在一块832g的香橙派AI香橙派AIpro进行YoloV5s算法的部署并使用一个外接的鱼眼USB摄像头…

Frrouting快速入门——OSPF组网(一)

FRR简介 FRR是FRRouting的简称,是一个开源的路由交换软件套件。其作者源自老牌项目quaga的成员,也可以算是quaga的新版本。 使用时一般查看此文档:https://docs.frrouting.org/projects/dev-guide/en/latest/index.html FRR支持的协议众多…

HarmonyOS APP应用开发项目- MCA助手(Day02持续更新中~)

简言: gitee地址:https://gitee.com/whltaoin_admin/money-controller-app.git端云一体化开发在线文档:https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/agc-harmonyos-clouddev-view-0000001700053733-V5注:…

系统安全体系架构规划框架

安全技术体系架构是对组织机构信息技术系统的安全体系结构的整体描述。安全技术体系架构框架是拥有信息技术系统的组织机构根据其策略的要求和风险评估的结果,参考相关技术体系构架的标准和最佳实践,结合组织机构信息技术系统的具体现状和需求&#xff0…

java通过jts获取点在线段中的位置

在Java中,可以使用JTS(Java Topology Suite)库来获取点在线段的垂足点位置。以下是一个简单的示例代码,展示了如何使用JTS获取点到线段的垂足点位置: 首先,确保你的项目中包含了JTS库。 import org.locati…

Python学习之小游戏--坦克大作战

今天跟视频学习了Python实现坦克大作战小游戏,挺有意思的,一起来玩吧~ 按空格发射子弹,上下左右键实现移动,ESC键无限复活。 import pygame,time,random from pygame.sprite import Sprite SCREEN_WIDTH800 SCREEN_HEIGHT500 BG…

C++(第四天----拷贝函数、类的组合、类的继承)

一、拷贝构造函数(复制构造函数) 1、概念 拷贝构造函数,它只有一个参数,参数类型是本类的引用。如果类的设计者不写拷贝构造函数,编译器就会自动生成拷贝构造函数。大多数情况下,其作用是实现从源对象到目…

JavaScript懒加载图像

懒加载图像是一种优化网页性能的技术,它将页面中的图像延迟加载,即在用户需要查看它们之前不会立即加载。这种技术通常用于处理大量或大尺寸图像的网页,特别是那些包含长页面或大量媒体内容的网站。 好处 **1. 加快页面加载速度&#xff1a…