1.抽象类的定义和使用
1.1.抽象类的定义与使用
抽象类只是在普通类的基础上扩充了一些抽象方法
而已,所谓的抽象方法指的是只声明而未实现的方法(没有方法体
)。所有抽象方法要求使用abstract
关键字来定义,并且抽象方法所在的类一定要使用abstract关键字来定义表示抽象类。定义一个抽象类示例:
abstract class Person{
private String name;
public String getName(){
return this.name;
}
public void setName(String name) {
this.name = name;
}
//{}为方法体,所有抽象方法上不包含方法体
public abstract void getPersonInfo();//抽象方法
}
抽象类中包含有抽象方法,而抽象方法不包含方法体,即没有具体实现,因此抽象类不能直接实例化对象
。所以对于抽象类的使用要遵循以下原则:
- 所有的抽象类
必须拥有子类
- 抽象类的子类必须
覆写抽象类的所有抽象方法
(子类不能是抽象类),方法覆写时一定要注意权限问题,权限尽量都使用public
!!!!注
:抽象类中的抽象方法必定只声明未实现,但是只声明未实现的却不一定是抽象方法(比如本地方法) - 抽象类的对象可以通过
对象多态性
由子类向上转型为其实例化 private、final都不能与abstract同时使用
抽象类的使用示例代码如下:
abstract class Person{
private String name;
public String getName(){
return this.name;
}
public void setName(String name) {
this.name = name;
}
//{}为方法体,所有抽象方法上不包含方法体
public abstract void getPersonInfo();//抽象方法
}
class Student extends Person{
public void getPersonInfo(){
System.out.println("叫我小可爱!");
}
}
public class Test{
public static void main(String[] args) {
//子类向上转型获得实例化对象
Person per = new Student();
//调用被子类覆写的方法
per.getPersonInfo();
}
}
//叫我小可爱!
如上操作是抽象类使用的标准操作并且是使用最多的形式,但是也有如下形式(定义内部类)出现:
abstract class Person{
private String name ; // 属性
public String getName(){ // 普通方法
return this.name;
}
public void setName(String name){
this.name = name ;
}
// {}为方法体,所有抽象方法上不包含方法体
public abstract void getPersonInfo() ; //抽象方法
public static Person getInstance(){
//定义抽象类的子类(内部类)
class Student extends Person{
//覆写抽象方法
public void getPersonInfo(){
System.out.println("我是靓仔");
}
}
return new Student();
}
}
public class Test{
public static void main(String[] args) {
Person per = Person.getInstance();
per.getPersonInfo();
}
}
//我是靓仔
如上这种形式属于非正常形式,不作为首选。
1.2.抽象类的相关规定
1.2.1
抽象类只是比普通类多定义了一些抽象方法而已,因此在抽象类中也允许提供构造方法
,并且子类也照样遵循对象实例化流程
,实例化子类时一定先调用父类构造方法
。抽象类中定义构造方法示例如下:
abstract class Person{
private String name;
public Person(){
System.out.println("Person");
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// {}为方法体,所有抽象方法上不包含方法体
public abstract void getPersonInfo() ; //抽象方法
}
class Studet extends Person{
public Studet(){
System.out.println("Student");
}
public void getPersonInfo(){
//空实现。
}
}
public class Test{
public static void main(String[] args) {
new Studet();
}
}
//Person
//Student
如果父类没有无参构造
,那么子类必须使用super指出使用的是父类哪个构造方法
,观察如下一段特殊代码:
abstract class A{
public A(){//4.调用父类构造
this.print();//5.子类已经覆写的抽象方法
}
public abstract void print();
}
class B extends A{
private int num = 100;
public B(int num){//2.调用子类构造方法
super();//3.首先要调用父类构造
this.num = num;//8.此时num被赋值
}
public void print(){//6.此时num还没被赋值但是被调用
System.out.println(this.num);//7.打印出num数据类型默认值
}
}
public class Test{
public static void main(String[] args) {
B b = new B(28);//1.实现子类实例化
b.print();//10.打印出赋值后的num
}
}
//0
//28
关于`对象实例化``的几个核心步骤:
- 进行
类加载
- 进行
类对象空间开辟
- 进行类对象中
属性初始化
(构造方法)
1.2.2
抽象类中允许不定义任何抽象方法,但是此时抽象类依然无法直接创建实例化对象。
abstract class A{
//其中没有抽象方法
public void print(){
//空实现,普通方法
}
}
public class Test{
public static void main(String[] args){
A a = new A(); // 错误: A是抽象的;,依旧无法实例化
}
}
1.2.3
抽象类一定不能使用final定义
,因为使用final定义的类不允许有子类,而抽象方法必须有子类
,相应的,抽象方法也不能用private定义
,因为抽象方法必须被覆写
。
1.2.4
抽象类分为内部抽象类和外部抽象类,关于内部抽象类:
子类只需要覆写外部抽象类中的直接抽象方法即可,内部抽象类的抽象方法不需要覆写
如果要覆写内部抽象类的抽象方法,继承类和抽象类结构相同就好了
- 如果现在外部抽象类中使用了static那么就是语法错误,但是
内部抽象类允许使用static
内部抽象类代码示例如下:
abstract class A{
public abstract void printA();
abstract class B{
public abstract void printB();
}
}
class X extends A{
public void printA(){}
class Y extends B{
public void printB(){}
}
}
内部抽象类使用static修饰示例如下:
abstract class A{
public abstract void printA();
static abstract class B{
public abstract void printB();
}
}
class X extends A.B{
public void printB(){}
}
2.模板设计模式(封装方法)——抽象类的实际应用
开闭原则(OCP
):一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭
。开闭原则是Java开发中一项基本的设计原则。
用代码实现星巴克咖啡和茶冲泡,冲泡过程:
Step. | 咖啡 | 茶 |
---|---|---|
1 | 将水煮沸 | 将水煮沸 |
2 | 用沸水冲泡咖啡 | 用沸水冲泡茶 |
3 | 将咖啡倒进杯子 | 将茶倒进杯子 |
4 | 加糖和牛奶 | 加牛奶 |
代码实现如下:
/**
* 咖啡冲泡
*/
class Coffee{
void preparePecipe(){
boilWater();
brewCoffeeGrings();
pourIntoCup();
addSugerAndMilk();
}
public void boilWater(){
System.out.println("将水煮沸");
}
public void brewCoffeeGrings(){
System.out.println("冲泡咖啡");
}
public void pourIntoCup(){
System.out.println("把咖啡倒入杯子");
}
public void addSugerAndMilk(){
System.out.println("加牛奶和糖");
}
}
/**
* 咖啡茶
*/
class Tea{
void preparePecipe(){
boilWater();
steepTeaBag();
pourIntoCup();
addLemon();
}
public void boilWater(){
System.out.println("将水煮沸");
}
public void steepTeaBag(){
System.out.println("冲泡茶");
}
public void pourIntoCup(){
System.out.println("把茶倒入杯子");
}
public void addLemon(){
System.out.println("加柠檬");
}
}
通过观察我们可以发现,上述代码两个类中代码有大量重复,因此我们应该整理,将部分内容进行抽取放进一个基类中,如下:
/**
* 饮料冲泡是一个抽象类
*/
abstract class CaffeeOrTea{
/**
* 现在采用同一个prepareRecipe()方法处理咖啡和茶
* 声明final是因为不希望子类将其覆写
*/
final void prepareRecipe(){
boilWater();
brew();
pourIntoCup();
addCondiment();
}
abstract void brew();
abstract void addCondiment();
void boilWater(){
System.out.println("将水煮沸");
}
void pourIntoCup(){
System.out.println("倒入杯中");
}
}
class Coffee extends CaffeeOrTea{
@Override
void brew(){
System.out.println("冲泡咖啡");
}
@Override
void addCondiment() {
System.out.println("加入糖和牛奶");
}
}
class Tea extends CaffeeOrTea{
@Override
void brew(){
System.out.println("冲泡茶");
}
@Override
void addCondiment() {
System.out.println("加入柠檬");
}
}
模板方法定义了一个算法的步骤骨架
,并允许子类为一个或者多个步骤提供具体实现
,将一些步骤延迟到子类
中。模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中某些步骤
。一个完整的模板模式的超类定义如下:
/**
* 基类声明为抽象类是为了让子类必须实现其操作
*/
abstract class AbstractClass{
/**
* 模板方法,被声明为final,防止被改变算法顺序
*/
final void templateMethoed(){
}
/**
* 具体延迟到子类中
*/
abstract void primitiveOperation1();
abstract void primitiveOperation2();
/**
* 具体操作且共用的方法定义在超类中,可以被模板方法或子类直接使用
*/
final void concreteOperation(){
//实现
}
/**
* 钩子方法是一类“默认不做事的方法”,子类可以视情况决定要不要覆盖他们
*/
void hook(){
//钩子方法
}
}
扩展前面星巴克饮料冲泡类,引入“钩子”方法,代码如下:
import java.util.Scanner;
abstract class CaffeeOrTea{
final void prepareRecipe(){
boilWater();
brew();
pourIntoCup();
if(customerWantCondiments()){
addCondiment();
}
}
abstract void brew();
abstract void addCondiment();
void boilWater(){
System.out.println("将水煮沸");
}
void pourIntoCup(){
System.out.println("倒入杯中");
}
/**
* 钩子方法,超类中通常是默认实现
* 子类选择性的覆写此方法
* @return
*/
boolean customerWantCondiments(){
return true;
}
}
class Tea extends CaffeeOrTea{
@Override
void brew(){
System.out.println("冲泡茶");
}
@Override
void addCondiment() {
System.out.println("加入柠檬");
}
}
class Coffee extends CaffeeOrTea{
@Override
void brew(){
System.out.println("冲泡咖啡");
}
@Override
void addCondiment() {
System.out.println("加入糖和牛奶");
}
/**
* 子类覆写了钩子方法,实现自定功能
*/
public boolean customerWantCondiments(){
String answer = getUserInput();
if(answer.equals("Y")){
return true;
}else{
return false;
}
}
private String getUserInput(){
String answer = null;
System.out.println("请问您要在咖啡中加入牛奶吗?");
Scanner scanner = new Scanner(System.in);
answer = scanner.nextLine();
return answer;
}
}
public class Test{
public static void main(String[] args) {
CaffeeOrTea tea = new Tea();
CaffeeOrTea coffee = new Coffee();
System.out.println("Making tea");
tea.prepareRecipe();
System.out.println("Making coffee");
coffee.prepareRecipe();
}
}
3.接口的定义与使用
抽象类
与普通类相比的最大特点就是约定了子类的实现要求
,但是抽象类存在着单继承局限,如果约定子类的实现要求避免单继承局限就需要使用接口
,在开发中,如果一个操作既可以用接口实现又可以用接口的话,优先使用接口
。
3.1.接口的基本概念
- 定义:
接口就是一个抽象方法和全局常量的集合
(在实际中,99%的接口只提供抽象方法,很少在接口中提供全局变量),在Java中接口使用interface
关键字定义。定义一个简单接口示例代码如下:
interface IMessage{
public static final String MSG = "我是靓仔";//全局常量
public abstract void print();//抽象方法
}
由于接口只是全局变量和抽象方法的集合,所以一下两种定义格式效果是一样的:
//定义一,完整格式
interface IMessage{
public static final String MSG = "我是靓仔";//全局常量
public abstract void print();//抽象方法
}
//定义二,简化格式
interface IMessage{
String MSG = "我是靓仔";//全局常量
void print();//抽象方法
}
接口中的方法即使没有定义成abstract也会被默认当成abstract方法
,毕竟接口定义的只是一个标准
,没有具体方法实现。
-
命名规范:父接口使用“I”开头,子接口去掉父接口开头的“I”在后面加上“Impl”。
eg:父接口IMyInterFace
子接口:MyInterFaceImpl -
多继承:子类想要使用接口,使用
implements
实现接口,同时,一个子类可以实现多个接口
(可以使用接口实现多继承),对于接口的子类必须覆写接口中所有抽象方法
,随后通过实例化子类再向上转型获得接口对象
。
interface IMessage{
public static final String MSG = "我是靓仔";//全局常量
public abstract void print();//抽象方法
}
interface INews{
public abstract String getName();
}
class MessageImpl implements IMessage,INews{
@Override
public String getName() {
return IMessage.MSG;//访问常量都建议加上类名称
}
@Override
public void print() {
System.out.println(getName());
}
}
public class Test{
public static void main(String[] args) {
IMessage m = new MessageImpl();//子类向上转型
m.print();//调用被子类覆写过的方法
INews n = (INews) m;
System.out.println(n.getName());
}
}
//我是靓仔
//我是靓仔
3.2.接口的使用限制
接口中只允许public权限
(不管常量还是抽象方法,都是public权限,即使不写权限修饰符,默认也是public,这个特点只有接口满足
)- 阿里编码规范:接口不要加任何修饰符,public也不要
- 当子类既需要实现接口,又要继承抽象类时,
先使用extends继承一个抽象类
,而后使用implements实现多个接口
interface IMessage{
public static final String MSG = "我是靓仔";//全局常量
public abstract void print();//抽象方法
}
interface INews{
public abstract String getName();
}
abstract class New{
//抽象类中方法前面的abstract不能省略,否则就是普通方法
public abstract void setName();
}
class MessageImpl extends New implements IMessage,INews{
@Override
public void setName() {
System.out.println("我是靓仔!");
}
@Override
public String getName() {
return IMessage.MSG;//访问常量都建议加上类名称
}
@Override
public void print() {
System.out.println(getName());
}
}
public class Test{
public static void main(String[] args) {
IMessage m = new MessageImpl();//子类向上转型
m.print();//调用被子类覆写过的方法
INews n = (INews) m;
System.out.println(n.getName());
New news = (New) m ;
news.setName();
}
}
//我是靓仔
//我是靓仔
//我是靓仔!
- 抽象类可以实现接口,当一个类声明实现一个接口而没有实现接口中的方法时,那么这个类必须是抽象类。
抽象类可以继承接口,但是接口不能继承抽象类
- 接口可以使用extends继承多个父接口(
接口的多继承
)
interface A{
public void printA();
}
interface B{
public void printB();
}
interface C extends A,B{
//接口多继承
public void print();
}
class Impl implements C{
@Override
public void printA(){}
@Override
public void printB(){}
@Override
public void print(){}
}
- 接口也可以定义一些内部结构,包括内部普通类、内部接口等,使用static定义的内部接口就相当于一个外部接口
interface A{
public void printA();
static interface D{
public void print();
}
}
class Impl implements A.D{
@Override
public void print(){}
}
3.3.接口的应用
接口在实际开发中有三大核心应用环境:
- 定义操作标准
- 表示能力
- 在分布式开发中暴露远程服务方法
描述一个概念电脑上可以使用任何USB设备(U盘、打印机等),代码示例如下:
/**
* 定义一个USB标准
*/
interface USB{
/**
* 安装驱动
*/
public void setUp();
/**
* 进行工作
*/
public void work();
}
/**
* 定义电脑类
*/
class Computer{
/**
* 插入USB设备
* @param usb
*/
public void plugin(USB usb){
usb.setUp();//安装
usb.work();//工作
}
}
/**
* 定义一个USB设备
*/
class UDisk implements USB{
@Override
public void setUp() {
System.out.println("安装打印机驱动");
}
@Override
public void work() {
System.out.println("打印机开始工作");
}
}
通过上述代码我们可以发现:接口和对象多态性结合之后,对于参数的统一更加明确,而且可以发现接口是在类之上的设计抽象。
4.工厂设计模式
引入场景:有一天,一个靓仔准备买笔记本,他到了商场发现两款比较喜欢的电脑,一款是Macbook Pro,另一款是SurfaceBook,根据以上场景绘制类图如下:
代码如下:
interface Computer{
void printComputer();
}
class MacbookProComputer implements Computer{
@Override
public void printComputer() {
System.out.println("MacbookPro");
}
}
class SuferaceBookComputer implements Computer{
@Override
public void printComputer() {
System.out.println("SufaceBook");
}
}
public class Client{
public void buyComputer(Computer computer){
computer.printComputer();
}
public static void main(String[] args) {
Client t = new Client();
t.buyComputer(new MacbookProComputer());
}
}
4.1.简单工厂模式
这时,这个靓仔又看上了一款Alienware笔记本,我们不得不回到客户端修改代码,使之支持Alienware笔记本,那么如何实现代码抽离或封装,使新的选择不干扰现有的部分呢?我们引入简单工厂模式。
简单工厂模式
:专门定义一个类用来创建其它类的实例,被创建的实例通常都有共同的父类。
相当于创建生产电脑的工厂,客户需要购买什么电脑只需要输入该类型编号便可以获得该电脑,将类的实例化交给工厂,易于解耦
。类图如下:
代码如下:
import java.util.Scanner;
interface Computer{
void printComputer();
}
class MacbookProComputer implements Computer{
@Override
public void printComputer() {
System.out.println("MackbookPro");
}
}
class SurfaceBookComputer implements Computer{
@Override
public void printComputer() {
System.out.println("SurfaceBook");
}
}
class AlienwareComputer implements Computer{
@Override
public void printComputer() {
System.out.println("Alienware");
}
}
class ComputerFactory{
public static Computer createComputer(String type){
Computer computer = null;
if(type.equals("macbook")){
computer = new MacbookProComputer();
}else if(type.equals("surface")){
computer = new SurfaceBookComputer();
}else if(type.equals("alien")){
computer = new AlienwareComputer();
}
return computer;
}
}
public class Client{
public void buyComputer(Computer computer){
computer.printComputer();
}
public static void main(String[] args) {
Client t = new Client();
Scanner in = new Scanner(System.in);
System.out.println("请输入您要购买的电脑型号:");
String type = in.nextLine();
Computer computer = ComputerFactory.createComputer(type);
t.buyComputer(computer);
}
}
以上就是一个简单工厂,概括:
- 一个产品抽象类
- 具体产品类
- 一个工厂
简单工厂优点
: - 简单易于实现
- 把类的实例化交给工厂,便于解耦合
简单工厂缺点
:
添加新的类需要修改工厂,违反OCP开闭原则(对扩展开放,对修改关闭)
4.2.工厂方法模式
工厂方法模式
:定义一个用来创建对象的接口,让子类决定实例化哪一个对象,在客户端中判断使用哪个工厂去创建对象。将之前的ComputerFactory抽象成一个接口,创建相应具体的工厂去实现该接口的方法,类图如下:
import java.util.Scanner;
interface Computer{
void printComputer();
}
class MacbookProComputer implements Computer{
@Override
public void printComputer() {
System.out.println("MackbookPro");
}
}
class SurfaceBookComputer implements Computer{
@Override
public void printComputer() {
System.out.println("SurfaceBook");
}
}
interface ComputerFactory{
Computer createComputer();
}
class MsFactory implements ComputerFactory{
@Override
public Computer createComputer() {
return new SurfaceBookComputer();
}
}
class AppleFactory implements ComputerFactory{
@Override
public Computer createComputer() {
return new MacbookProComputer();
}
}
public class Client{
public void buyComputer(Computer computer){
computer.printComputer();
}
public static void main(String[] args) {
Client t = new Client();
ComputerFactory factory = new AppleFactory();
t.buyComputer(factory.createComputer());
}
}
工厂方法是针对每个产品提供一个工厂类,在客户端中判断使用哪个工厂类去创建对象
。
对比简单工厂模式和工厂方法模式:
- 对于简单工厂模式而言,创建对象的逻辑判断放在工厂类中,客户不感知具体的类,但是其
违背了开闭原则(OCP)
,如果要增加新的具体类,就必须修改工厂类 - 对于工厂方法而言,是通过扩展来新增具体的类,符合开闭原则,但是在客户端就必须要感知到具体的工厂类,也就是
将判断逻辑由简单工厂挪到客户端
工厂模式横向扩展很方便
,加入该工厂又有新的产品MacBook Air要生产,那么只需要创建相应的工厂类和产品类去实现抽象工厂接口和抽象产品接口即可,而不用去修改原有已经存在的代码
工厂方法概要:
1.一个抽象产品类
2.多个具体产品类
3.一个抽象工厂
4.多个具体工厂——每个具体产品对应一个具体工厂
工厂方法优点
:
1.降低了代码耦合度,对象的生成交给子类完成
2.实现开闭原则,每次添加产品无需修改原有代码只需扩展
工厂方法缺点
:
1.增加了代码量,每个具体产品都要一个具体工厂
2.当增加抽象产品,也就是添加一个其他产品族,需要修改代码,未被OCP
4.3.抽象工厂模式
抽象工厂模式
:提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类
工厂方法模式和抽象工厂模式基本类似,可以这么理解,当工厂只生产一个产品的时候,即为工厂方法模式,而工厂如果生产两个或以上的商品即变为抽象工厂模式,我们在抽象过程中新增创建系统的方法,并由示例工厂去实现,类图如下:
代码实现如下:
interface Computer{
void printComputer();
}
class MacbookProComputer implements Computer{
@Override
public void printComputer() {
System.out.println("MackbookPro");
}
}
class SurfaceBookComputer implements Computer{
@Override
public void printComputer() {
System.out.println("SurfeceBook");
}
}
interface OperatingSystem{
void printSystem();
}
class MacOsSystem implements OperatingSystem{
@Override
public void printSystem() {
System.out.println("This is mac os");
}
}
class Windows8System implements OperatingSystem{
@Override
public void printSystem() {
System.out.println("This is window8");
}
}
interface ProdectionFactory{
Computer createComputer();
OperatingSystem createSystem();
}
class AppleFactory implements ProdectionFactory{
@Override
public Computer createComputer() {
return new MacbookProComputer();
}
@Override
public OperatingSystem createSystem() {
return new MacOsSystem();
}
}
class MsFactory implements ProdectionFactory{
@Override
public Computer createComputer() {
return new MacbookProComputer();
}
@Override
public OperatingSystem createSystem() {
return new MacOsSystem();
}
}
public class Client{
public void buyComputer(Computer computer){
computer.printComputer();
}
public void use(OperatingSystem s){
s.printSystem();
}
public static void main(String[] args) {
Client c = new Client();
ProdectionFactory factory = new AppleFactory();
Computer computer = factory.createComputer();
OperatingSystem system = factory.createSystem();
c.buyComputer(computer);
c.use(system);
}
}
抽象工厂优点
:
- 代码解耦
- 实现多个产品族(相关联产品组成的家族)
- 很好的满足OCP开放封闭原则
- 抽象工厂模式中,我们可以定义实现不知一个接口,一个工厂也可以实现不止一个产品类,对于复杂对象的生产相对灵活且容易扩展
抽象工厂缺点
: - 扩展产品族相当麻烦,而且扩展产品族会违反OCP原则,因为要修改所有工厂
- 由于抽象工厂模式是工厂方法模式的扩展,所以总体来说,很笨重
总结:
- 简单工厂模式最大的优点就是工厂内有具体的逻辑去判断生产什么产品,将类的实例化交给工厂,这样我们需要什么工厂就只需要修改工厂而不需要去修改客户端,对于客户端来说降低了与具体产品的依赖
- 工厂方法模式是简单工厂的扩展,工厂方法模式把原先简单工厂中的实现哪个类的逻辑判断交给了客户端,如果添加功能只需要修改客户端和添加具体的功能,不用修改之前的类
- 抽象工厂模式进一步扩展了工厂方法模式,它把原先的工厂方法模式中只能有一个抽象产品不能添加产品族的缺点客服了,抽象工厂模式不仅仅遵循了OCP原则,而且可以添加许多产品,具体工厂也不止能生产单一产品而是生产一组产品,抽象工厂也是声明一组产品,对应扩展更加灵活,但是要扩展族系就会很笨重
JDK中用到工厂方法的典型操作:
- Collection中的Iterator方法(集合类中的迭代器)
- java.util包中的sql相关操作
5.接口设计模式——代理模式
代理模式:两个子类共同实现一个接口,其中一个子类负责实现真实业务,另一个子类完成辅助真是业务主体的操作。代理模式范例:
interface ISubject{
public void buyComputer(); //核心功能是买电脑
}
class RealSubject implements ISubject{
@Override
public void buyComputer() {
System.out.println("买一台外星人电脑");
}
}
class ProxySubject implements ISubject{
//真实的操作
private ISubject subject;
public ProxySubject(ISubject subject){
this.subject = subject;
}
public void prodeceComputer(){
System.out.println("生产一台外星人电脑");
}
public void saleAfter(){
System.out.println("外星人电脑售后团队");
}
@Override
public void buyComputer() {
this.prodeceComputer();//真实操作之前的准备
this.subject.buyComputer();//强调真实业务
this.saleAfter();//强调收尾工作
}
}
class Factory{
public static ISubject getInstance(){
return new ProxySubject(new RealSubject());
}
}
public class Code{
public static void main(String[] args) {
ISubject subject = Factory.getInstance();
subject.buyComputer();
}
}
代理模式的本质:所有的真实业务操作都会有一个与之相符的工具类共同完成。
6.抽象类与接口的区别
No. | 区别 | 抽象类(abstract) | 接口(interface) |
---|---|---|---|
1 | 组成结构 | 普通类 + 抽象方法 | 抽象方法 + 全局常量 |
2 | 权限 | 各种权限 | public |
3 | 子类使用 | 使用extends关键字继承抽象类 | 使用implements关键字实现接口 |
4 | 关系 | 一个抽象类可以实现若干接口 | 接口不能继承抽象类,但是接口可以使用extends关键字继承多个父接口 |
5 | 子类限制 | 一个子类只能继承一个抽象类 | 一个子类可以实现多个接口 |
除了单继承局限之外,实际上使用抽象类和接口都是类似的,在实际开发中,抽象类的设计比借口复杂:
- 接口是Java的核心
- 在接口和抽象类两者之间权衡,
优先使用接口
抽象类是模板
,有层次感
,接口则更关心行为与混合