1)掌握抽象类和接口的实例化操作。
2)掌握模板设计的作用。
3)掌握工厂设计模式的作用。
4)掌握代理设计模式的作用。
5)掌握适配器模式的作用。
6)掌握抽象类和接口的使用区别。
2.1 为抽象类和接口实例化
在java中,可以通过对象的多态性,为抽象类和接口实例化,这样在使用抽象类和接口的时候,就可以调用本子类中所覆写过的方法。之所以抽象类和接口不能直接实例化,是因为其内部包含了抽象方法,抽象方法本身是未实现的方法,所以无法调用。
通过对象多态性可以发现,子类发生了向上转型关系之后,所调用的全部方法,都是被覆写过的方法。
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public abstract class A {//定义抽象类A
public abstract void print();//定义抽象方法print()
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class B extends A {//定义子类,继承
// 抽象类
@Override
public void print() {//覆写抽象方法
System.out.println("hello world!!");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class AbstractCaseDemo01 {
public static void main(String args[]) {
A a = new B();
a.print();
}
}
运行结果:hello world!!
可以继续利用此概念,为接口实例化。
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public abstract class A {//定义抽象类A
public abstract void print();//定义抽象方法print()
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class B extends A {//定义子类,继承
// 抽象类
@Override
public void print() {//覆写抽象方法
System.out.println("hello world!!");
}
}
public class ThisDemo06 {
public static void main(String args[]) {
A a=new B();//通过子类抽象为类实例化
a.print();
}
}
证明,如果要想使用抽象类和接口,则只能按照以上操作完成。
2.2 抽象类的实际应用--模板设计
首先看这样一个场景:假设人分学生和工人,学生和工人都可以说话,但是学生和工人说话的内容不一样,也就是说,说话这个功能应该是具体功能,而说话的内容就要由学生或工人来决定了。所以此时可以使用抽象类实现这个场景。
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public abstract class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public void say() {//人说话是一个具体的功能
System.out.println(getContent());
}
public abstract String getContent();//说话的内容由子类决定
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class Student extends Person {
private float score;
public Student(String name, int age,float score) {
super(name, age);//调用父类中的构造方法
this.score=score;
}
@Override
public String getContent() {
return "学生信息 --> 姓名:"+super.getName()+
"; 年龄:"+super.getAge()+
"; 成绩:"+this.score;
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class Worker extends Person {
private float salary;
public Worker(String name, int age, float salary) {
super(name, age);//调用父类中的构造方法
this.salary = salary;
}
@Override
public String getContent() {
return "工人信息 --> 姓名:" + super.getName() +
";年龄:" + super.getAge() +
";工资:" + this.salary;
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class AbstractCaseDemo02 {
public static void main(String args[]){
Person per1=null;//声明Person对象
Person per2=null;//声明Person对象
per1=new Student("张三",20,99.0f);//学生这个人
per2=new Worker("李四",30,3000.0f);//工人是一个人
per1.say();
per2.say();
}
}
运行结果:
学生信息 --> 姓名:张三; 年龄:20; 成绩:99.0
工人信息 --> 姓名:李四;年龄:30;工资:3000.0
这里,抽象类就相当于一个模板。
就像现实中的各种模板,只有模板填写之后才会有意义。
2.3 接口的实际应用--制定标准。(一定要按照规定的标准做)
接口在实际应用中更多的作用是指定标准的。比如说“U盘和打印机都可以插在电脑上使用,因为他们都实现了USB标准的接口,对于电脑来说,只要符合USB接口标准的设备都可以插进来”
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public interface USB {
public void start();//USB设备开始工作
public void stop();//USB设备结束工作
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/8/31
*/
public class Computer {
//电脑上可以插入USB设备,向上转型,这里就相当于是个接口,
// 只有符合这个接口的标准的类的对象(即只有继承这个接口的类的对象),才能被这个方法调用
public static void plugin(USB usb){
usb.start();
System.out.println("=======USB 设备工作=======");
usb.stop();
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Flash implements USB {
@Override
public void start() {
System.out.println("U盘开始工作。");
}
@Override
public void stop() {
System.out.println("U盘停止工作。");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Print implements USB {
@Override
public void start() {
System.out.println("打印机开始工作。");
}
@Override
public void stop() {
System.out.println("打印机停止工作。");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class InterfaceCaseDemo02 {
public static void main(String args[]){
Computer.plugin(new Flash());
Computer.plugin(new Print());
}
}
运行结果:
U盘开始工作。
=======USB 设备工作=======
U盘停止工作。
打印机开始工作。
=======USB 设备工作=======
打印机停止工作。
2.4、工厂设计模式(接口应用)
工厂设计模式是在java开发中最常使用的一种设计模式。
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public interface Fruit {//定义一个水果接口
public void eat();//吃水果
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Apple implements Fruit {
@Override
public void eat() {
System.out.println("---吃苹果。");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Orange implements Fruit {
@Override
public void eat() {
System.out.println("----吃橘子");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class InterfaceCaseDemo03 {
public static void main(String args[]){
Fruit f=new Apple();//实例化接口
f.eat();
}
}
运行结果:---吃苹果。
这样的代码可以使么?有问题吗?
分析:
主方法:就应该表示客户端。主方法的代码越少越好。此时,直接在主方法中指定了要操作的子类,如果要更换子类,肯定要修改客户端。就表示跟特定的子类耦合在一起了。
JVM工作原理:程序-》JVM(相当于客户端)-》操作系统
问题的解决:客户端通过过渡端,得到特定子类的接口实例,返回接口实例给客户端,接口实例调用接口中的方法。
此过渡端,在程序中就称为工厂设计(工厂类)
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public interface Fruit {//定义一个水果接口
public void eat();//吃水果
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Apple implements Fruit {
@Override
public void eat() {
System.out.println("---吃苹果。");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Orange implements Fruit {
@Override
public void eat() {
System.out.println("----吃橘子");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Factory {//定义工厂类
public static Fruit getInstance(String className){//注意这里的方法是static修饰的,因为在主方法中是Factory调用
Fruit f=null;
if ("apple".equals(className)){//判断是否要的是苹果的子类
f=new Apple();
}
if ("orange".equals(className)){//判断是否要的是橘子的子类
f=new Orange();
}
return f;
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class InterfaceCaseDemo04 {
public static void main(String args[]){
Fruit f=Factory.getInstance("apple");//实例化接口
f.eat();
}
}
运行结果:---吃苹果。
流程是:客户端(主方法)通过工厂类的getInstance()方法,通过传入的参数判断,该获取实例化哪个子类的实例,然后把获取的实例通过getInstance()方法返回(return)该实例给主方法中的借口实力,最后通过接口实例调用所需方法。
2.5 代理设计模式(接口应用)
假设现在有以下这种情况:
1)张三借了李四500块钱。
2)李四不换,张三生气。
3)张三找到王五,王五是讨债公司。
4)王五准备了刀枪
5)把李四欠的钱换回来了。
也就是张三找李四借钱,王五代理了张三。
代理设计:也是在java中应用比较多的设计模式,所谓的代理设计就是指一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务。就好比生活中经常用到的代理上网那样,客户通过网络代理链接网络,由代理服务器完成用户权限,上网操作相关操作。
分析结果:不管代理操作也好,真是操作也好,其共同目的就是上网,所以用户关心的是如何上网,至于如何操作的,用户不关心
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public interface Network {
public void browse();//浏览
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Real implements Network {//真实的上网操作
@Override
public void browse() {
System.out.println("上网浏览信息");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class Proxy implements Network {//代理类
private Network network;//代理对象
public Proxy(Network network) {//初始化,把真实对象传给代理对象,向上转型操作
this.network = network;
}
public void check(){
System.out.println("检查用户是否合法。");
}
@Override
public void browse() {
this.check();
this.network.browse();//调用真实的主题操作,这里调用的是真实类里的对象
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class ProxyDemo {
public static void main(String args[]){
Network net=null;
/**
* 指定代理操作,这里两次向上转型操作,第一次向上是实例化代理类,
* 第二次向上转型是括号中,把真实类对象传入,以便在代理类中调用真实类中的方法。
*/
net=new Proxy(new Real());
net.browse();//客户只关心上网浏览一个操作。
}
}
运行结果:
检查用户是否合法。
上网浏览信息
代理操作流程
2.5 适配器模式
此设计,在日后学习java的图形界面用的非常多。
在java中,一个子类实现了一个接口,则肯定在子类中覆写此接口中全部抽象方法。那么这样一来,如果一个借口中提供的抽象方法过多,而且没有必要全部实现的话,肯定很浪费,此时就需要一个中间过渡,但是此过渡又不希望被直接调用,所以将此过渡器定义成抽象类更合适,即:一个接口首先被一个抽象类(此抽象类成为适配器类)继承,并在此抽象类中实现若干方法(方法体为空),则以后的子类直接继承此抽象类(适配器),就可以有选择的覆写所需方法了。
一个抽象类可以实现一个接口,那么对于抽象类的子类,则必须覆写抽象类和接口的全部(未实现的)抽象方法。(即如果接口中的某类方法在抽象类中实现了(覆写了),那么在抽象类的子类中就可以不用覆写了。因为继承,在父类中的方法,被子类继承了,相当于子类腹泻了,子类照样可以调用,覆写该方法。)
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public interface Window {//定义Window接口,表示窗口操作
public void open();//打开
public void close();//关闭
public void activated();//窗口活动
public void iconified();//窗口最小化
public void deiconified();//窗口恢复大小
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public abstract class WindowAdapter implements Window {
@Override
public void open() {
}
@Override
public void close() {
}
@Override
public void activated() {
}
@Override
public void iconified() {
}
@Override
public void deiconified() {
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class WindowImpl extends WindowAdapter {
@Override
public void open() {
super.open();
System.out.println("窗口打卡。");
}
@Override
public void close() {
super.close();
System.out.println("窗口关闭。");
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class AdapterDemo {
public static void main(String args[]){
Window window=new WindowImpl();
window.open();
window.close();
}
}
运行结果:
窗口打卡。
窗口关闭。
此种设计思路,在java的图形界面编程上使用非常多。但在javaee上使用不常见。
2.6 内部类的扩展
之前已经讲过内部类的概念,实际上在一个抽象类中也可以包含一个接口。
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public abstract class C {//定义抽象类
public abstract void printA();//抽象方法
interface B {//定义内部接口
public void printB();//定义抽象方法
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class X extends C {//继承抽象类
@Override
public void printA() {
System.out.println("HELLO-->A");
}
class Y implements B {//定义内部类实现内容接口
@Override
public void printB() {
System.out.println("HELLO-->B");
}
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class InnerExtDemo01 {
public static void main(String args[]){
C.B b=new X().new Y();//参考前面内部类的知识,实现内部类实例的方法:外部类.内部类 内部类对象=外部类对象.new 内部类
b.printB();
}
}
运行结果:
HELLO-->B
含有内部接口测抽象类的子类,必须也要定义内部类继承该接口
反之,在一个接口中也可以定义一个抽象类。
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public abstract class C {//定义抽象类
public abstract void printA();//抽象方法
abstract class B {//定义内部抽象类
public abstract void printB();//定义抽象方法
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class X extends C {//继承抽象类
@Override
public void printA() {
System.out.println("HELLO-->A");
}
class Y extends B {//继承抽象类
@Override
public void printB() {
System.out.println("HELLO-->B");
}
}
}
/**
* Describe:
*
* Author: Lixm
* Date: 2018/9/3
*/
public class InnerExtDemo02 {
public static void main(String args[]){
C.B b=new X().new Y();//参考前面内部类的知识,实现内部类实例的方法:外部类.内部类 内部类对象=外部类对象.new 内部类
b.printB();
}
}
含有内部抽象类的接口,对于继承他的子类来说,除了要覆写接口中的抽象方法,还要专门定义一个内部类继承抽象类,并覆写全部抽象类。
但是,从个人开发来说,此种设计不太常见,因为代码有些混乱。
重要提示:
在开发中,一个类永远不要去继承一个已经实现好的类,要么继承抽象类,要没实现接口,如果两个类同事都可以使用的话,优先使用接口,避免单继承的局限。
1)抽象类和接口类的实例化,通过多态性(向上转型,向下转型)。
2)抽象类表示一个模板,接口表示一个标准。
3)常见的设计模式:模板设计,工厂设计,代理设计,适配器设计。