抽象类与接口的应用—设计模式
抽象类及接口的实例化
抽象类及接口不能直接实例化,需要依靠子类,子类需要实例化接口或者抽象类中的全部抽象方法。
在java中可以通过对象的多态性,为抽象类和接口实例化,这样在使用抽象类和接口的时候就可以调用本子类中锁覆写过的方法了。
之所以抽象类和接口不能直接实例化,是因为其内部包含了抽象方法,抽象方法本身都是未实现的方法,所以无法调用。
通过对象多态性可以发现,子类发生了向上转型关系以后,所调用的全部方法都是被覆写过的方法。
abstract class A{ // 定义抽象类A
public abstract void print() ; // 定义抽象方法print()
};
class B extends A { // 定义子类,继承抽象类
public void print(){ // 覆写抽象方法
System.out.println("Hello World!!!") ;
}
};
public class AbstractCaseDemo01{
public static void main(String args[]){
A a = new B() ; // 通过子类为抽象类实例化
a.print() ;
}
};
interface A{ // 定义接口
public abstract void print() ; // 定义抽象方法print()
};
class B implements A { // 定义子类,实现接口
public void print(){ // 覆写抽象方法
System.out.println("Hello World!!!") ;
}
};
public class InterfaceCaseDemo01{
public static void main(String args[]){
A a = new B() ; // 通过子类为抽象类实例化
a.print() ;
}
};
如果要使用抽象类或者接口,只能按照以上的操作进行。
抽象类的应用
模板设计的作用
抽象类的作用------定义模板。
代码实现上面的场景:
abstract class Person{
private String name ; // 定义name属性
private int age ; // 定义age属性
public Person(String name,int age){
this.name = name ;
this.age = age ;
}
public String getName(){
return this.name ;
}
public int getAge(){
return this.age ;
}
public void say(){ // 人说话是一个具体的功能
System.out.println(this.getContent()) ; // 输出内容
}
public abstract String getContent() ; // 说话的内容由子类决定
};
class Student extends Person{
private float score ;
public Student(String name,int age,float score){
super(name,age) ; // 调用父类中的构造方法
this.score = score ;
}
public String getContent(){
return "学生信息 --> 姓名:" + super.getName() +
";年龄:" + super.getAge() +
";成绩:" + this.score ;
}
};
class Worker extends Person{
private float salary ;
public Worker(String name,int age,float salary){
super(name,age) ; // 调用父类中的构造方法
this.salary = salary ;
}
public String getContent(){
return "工人信息 --> 姓名:" + super.getName() +
";年龄:" + super.getAge() +
";工资:" + this.salary ;
}
};
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() ; // 工人说工人的话
}
};
接口的应用
接口的作用------制定标准。
interface USB{ // 定义了USB接口
public void start() ; // USB设备开始工作
public void stop() ; // USB设备结束工作
}
class Computer{
public static void plugin(USB usb){ // 电脑上可以插入USB设备
usb.start() ;
System.out.println("=========== USB 设备工作 ========") ;
usb.stop() ;
}
};
class Flash implements USB{
public void start(){ // 覆写方法
System.out.println("U盘开始工作。") ;
}
public void stop(){ // 覆写方法
System.out.println("U盘停止工作。") ;
}
};
class Print implements USB{
public void start(){ // 覆写方法
System.out.println("打印机开始工作。") ;
}
public void stop(){ // 覆写方法
System.out.println("打印机停止工作。") ;
}
};
public class InterfaceCaseDemo02{
public static void main(String args[]){
Computer.plugin(new Flash()) ;
Computer.plugin(new Print()) ;
}
};
接口的核心就是—标准。
工厂设计模式的作用
工厂设计模式是在java开发中最常使用的一种设计模式。
1,什么是工厂?
2,工厂有哪些作用?
1,代码,实现工厂:
interface Fruit{ // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
public class InterfaceCaseDemo03{
public static void main(String args[]){
Fruit f = new Apple() ; // 实例化接口
f.eat() ;
}
};
以上的代码设计,是否OK?
分析:
主方法,应该就表示一个客户端,主方法的代码越少越好。此时直接在主方法在中指定要操作的子类,如果要更换子类,则肯定需要客户端,这就非常不合理。哪里不合理—主类客户端和特定的子类紧密的耦合在一起了,代码维护性非常差,非常不利于代码扩展。
此过渡端在程序中就是工厂。
客户端通过一个过渡端去找到子类实例,客户端的额操作以接口为标准,过渡端在程序中就称为工厂设计。
2,使用工厂模式,进行解耦合优化:
interface Fruit{ // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
class Factory{ // 定义工厂类
public static Fruit getInstance(String className){
Fruit f = null ;
if(className.equals("apple")){ // 判断是否要的是苹果的子类
f = new Apple() ;
}
if(className.equals("orange")){ // 判断是否要的是橘子的子类
f = new Orange() ;
}
return f ;
}
};
public class InterfaceCaseDemo04{
public static void main(String args[]){
Fruit f = Factory.getInstance("apple") ; // 实例化接口
//Fruit f = Factory.getInstance(null) ; // 实例化接口
f.eat() ;
}
};
以上代码虽然使用了工厂,设计非常合理了,但是如果给个空值,程序就空指针挂掉了。
3,优化工厂
interface Fruit{ // 定义一个水果接口
public void eat() ; // 吃水果
}
class Apple implements Fruit{
public void eat(){
System.out.println("** 吃苹果。") ;
}
};
class Orange implements Fruit{
public void eat(){
System.out.println("** 吃橘子。") ;
}
};
class Factory{ // 定义工厂类
public static Fruit getInstance(String className){
Fruit f = null ;
if("apple".equals(className)){ // 判断是否要的是苹果的子类
f = new Apple() ;
}
if("orange".equals(className)){ // 判断是否要的是橘子的子类
f = new Orange() ;
}
return f ;
}
};
public class InterfaceCaseDemo05{
public static void main(String args[]){
Fruit f = Factory.getInstance(args[0]) ; // 实例化接口
if(f!=null){ // 判断是否取得实例
f.eat() ;
}
}
};
以上的代码,其实依然有隐患,字符串,很容易在编写时候出错,代码不够健壮,依然有优化的空间。
可以通过使用枚举进行优化。
代理设计模式的作用
代理上网服务器的例子:
客户端通过代理服务器连接上网服务器连接到外网,上网服务器只管连接,代理服务器会完成,网站访问限制,信息过滤,等等,但是客户端要的功能就是能不能上网,不管是代理服务器还是上网服务器,对客户端来说不care,客户端只关心能不能上网。这个时候就可以使用代理。
interface Network{
public void browse() ; // 浏览
}
class Real implements Network{
public void browse(){
System.out.println("上网浏览信息") ;
}
};
class Proxy implements Network{
private Network network ; // 代理对象
public Proxy(Network network){
this.network = network ;
}
public void check(){
System.out.println("检查用户是否合法。") ;
}
public void browse(){
this.check() ;
this.network.browse() ; // 调用真实的主题操作
}
};
public class ProxyDemo{
public static void main(String args[]){
Network net = null ;
net = new Proxy(new Real()) ;// 指定代理操作
net.browse() ; // 客户只关心上网浏览一个操作
}
};
代理类里面需要传入一个代理对象。
代理类的最终目标也是完成真实操作,但是比真实类(被代理对象)多了一些其他功能,但是这些功能可能与具体的真是操作无关,
代理类,完成的是与真实具体操作相关的一些其他操作,完成具体业务中不想处理的功能。这是代理的功能。
代理类比真实类完成更多的功能。代理类完成与具体业务无关的其他操作,代理类完成那些具体业务不想处理的功能。
代理类比真实类完成更多的功能。代理类完成与具体业务无关的其他操作,代理类完成那些具体业务不想处理的功能。
适配器设计模式的作用
如果一个子类实现了一个接口,则肯定在子类中必须覆写接口中的全部抽象方法,那么这样一来,如果一个接口中提供的抽象方法过多,而且没有必要全部实现的话,就显得非常浪费。
此时,就可以通过适配器解决这种问题。
在接口和实现类中间增加一个适配器类。
适配器类使用抽象类表示,抽象类可以把接口中的抽象方法都实现,但是不给出具体的实现方法,也就是说有方法体,但是方法体是空的;最后实现类继承抽象类,在实现类中根据需要去实现具体用到的某个或者某些方法。
interface Window{ // 定义Window接口,表示窗口操作
public void open() ; // 打开
public void close() ; // 关闭
public void activated() ; // 窗口活动
public void iconified() ; // 窗口最小化
public void deiconified();// 窗口恢复大小
}
abstract class WindowAdapter implements Window{
public void open(){} ; // 打开
public void close(){} ; // 关闭
public void activated(){} ; // 窗口活动
public void iconified(){} ; // 窗口最小化
public void deiconified(){};// 窗口恢复大小
};
class WindowImpl extends WindowAdapter{
public void open(){
System.out.println("窗口打开。") ;
}
public void close(){
System.out.println("窗口关闭。") ;
}
};
public class AdapterDemo{
public static void main(String args[]){
Window win = new WindowImpl() ;
win.open() ;
win.close() ;
}
};
抽象类与接口的使用区别
在一个抽象类中定义一个接口。
在一个接口中也可以定义一个抽象类。
不使用内部类中的接口,编译运行肯定是没问题的。
abstract class A{ // 定义抽象类
public abstract void printA() ; // 抽象方法
interface B{ // 定义内部接口
public void printB() ; // 定义抽象方法
}
};
class X extends A{ // 继承抽象类
public void printA(){
System.out.println("HELLO --> A") ;
}
class Y implements B{ // 定义内部类实现内部接口
public void printB(){
System.out.println("HELLO --> B") ;
}
};
};
public class InnerExtDemo01{
public static void main(String args[]){
A a = new X();
a.printA() ;
}
};
使用内部类中的接口:
abstract class A{ // 定义抽象类
public abstract void printA() ; // 抽象方法
interface B{ // 定义内部接口
public void printB() ; // 定义抽象方法
}
};
class X extends A{ // 继承抽象类
public void printA(){
System.out.println("HELLO --> A") ;
}
class Y implements B{ // 定义内部类实现内部接口
public void printB(){
System.out.println("HELLO --> B") ;
}
};
};
public class InnerExtDemo01{
public static void main(String args[]){
A.B b = new X().new Y() ;
b.printB() ;
}
};
interface A{ // 定义接口
public void printA() ; // 抽象方法
abstract class B{ // 定义内部抽象类
public abstract void printB() ; // 定义抽象方法
}
};
class X implements A{ // 实现接口
public void printA(){
System.out.println("HELLO --> A") ;
}
class Y extends B{ // 继承抽象类
public void printB(){
System.out.println("HELLO --> B") ;
}
};
};
public class InnerExtDemo02{
public static void main(String args[]){
A.B b = new X().new Y() ;
b.printB() ;
}
};
但是这样的嵌套使用很少,因为破坏了程序的结构。