精华内容
下载资源
问答
  • 在上文 与接口相关的设计模式(1) 中,详细介绍了定制服务模式和适配器模式,下面我们来看第三种与接口相关的模式:代理模式。代理模式定义:为对象提供一种代理,以控制对这个对象的访问。分类: 远程代理(Remote...

    在上文 与接口相关的设计模式(1) 中,详细介绍了定制服务模式和适配器模式,下面我们来看第三种与接口相关的模式:代理模式。

    代理模式

    定义:为对象提供一种代理,以控制对这个对象的访问。

    分类:

    1. 远程代理(Remote Proxy)—为不同地理的对象提供局域网代表对象。(类似于客户端和服务器端)
    2. 虚拟代理(Virtual Proxy)—根据需要将资源消耗很大的对象进行延迟,真正需要的时候才进行创建。(网页中图片的加载,先用一张虚拟的图片进行显示,等图片加载完成后再进行显示)
    3. 保护代理(Protect Proxy)—控制用户的访问权限。(发帖功能)
    4. 智能引用代理(Smart Reference Proxy)—提供对目标对象一些额外的服务。(火车站代售处为火车站代理)

    以下以智能引用代理为例,介绍代理的两种实现方式:静态代理和动态代理。

    • 静态代理:代理和被代理对象在代理之前是确定的,它们都实现了相同的接口或者继承相同的抽象类。

    下面为简单示例,演示一个汽车对象被代理实现计时:

    package com.proxy;
    
    public interface Moveable {//汽车的行驶功能
        void move();
    }

    如果没有代理,汽车行驶的计时功能要在汽车本身行驶时实现:

    package com.proxy;
    
    import java.util.Random;
    
    public class Car implements Moveable{
        @Override
        public void move() {
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
    
            try{
                Thread.sleep(new Random().nextInt(1000));
                System.out.println("行驶中");
            }catch(InterruptedException e){
                e.printStackTrace();
            }
    
            long endTime = System.currentTimeMillis();
            System.out.println("汽车行驶结束,行驶时间为:"+(endTime-startTime)+" ms");
        }
    }
    

    对于这种情景,我们可以创建一个代理来专门实现计时功能,如下:

    package com.proxy;
    
    public class CarProxy1 extends Car{
    
        @Override
        public void move() {
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
            super.move();
            long endTime = System.currentTimeMillis();
            System.out.println("汽车行驶结束,行驶时间为:"+(endTime-startTime)+" ms");
        }
    }
    

    此时在Car类中的move方法可以只行驶,将计时功能交给代理去实现,Car类中的move方法代码如下:

    public void move() {
    
            try{
                Thread.sleep(new Random().nextInt(1000));
                System.out.println("行驶中");
            }catch(InterruptedException e){
                e.printStackTrace();
            }
    
        }

    现在我们要访问汽车时不用再直接实例化Car类,而是通过访问它的代理:CarProxy1实例,如下:

    package com.proxy;
    
    public class Test {
        public static void main(String []args){
           CarProxy1 car  = new CarProxy1();
           car.move();
        }
    }
    

    以上是通过继承的方式实现,还可以通过组合的方式实现,即不通过继承Car类,而是通过包装Car类来调用Car实例的行驶功能。代码如下:

    package com.proxy;
    
    public class CarProxy2 implements Moveable{
    
        private Car car;
        public CarProxy2(Car car) {
            super();
            this.car = car;
        }
    
        @Override
        public void move() {
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
            car.move();
            long endTime = System.currentTimeMillis();
            System.out.println("汽车行驶结束,行驶时间为:"+(endTime-startTime)+" ms");
        }
    }

    通过组合方式创建的代理类,在实例化代理前,需要先实例化Car对象,代码如下:

    package com.proxy;
    
    public class Test {
        public static void main(String []args){
            Car car = new Car();
            CarProxy2 carProxy2  = new CarProxy2(car);
            carProxy2.move();
        }
    }
    

    与适配器模式中的类的适配器模式、对象的适配器模式相似,代理模式中组合方式比继承方式更灵活,推荐使用组合方式。比如再对Car实现日志记录等功能,使用继承方式则要再新建一个代理继承CarProxy1,之后再添加功能就要无限的向下继承,难于维护。

    动态代理

    上例中对汽车创建了一个时间记录代理,那么如果我们要对火车、飞机都记录时间呢?就需要分别对火车、飞机创建代理类。我们需要一个方法来把记录时间这个代理抽离出来,这样当需要对不同的交通工具实现记录时间功能的时候,直接运用这个抽离出的代理,这样可大大减少代码的重用率。这就引出了动态代理。

    动态代理就是动态产生代理,实现对不同类,不同方法的代理。下面来看JDK动态代理。以下为JDK动态代理的实现机制:
    这里写图片描述
    如图所示,JDK的动态代理其实就是在代理类ProxySubject与被代理类RealSubject之间加入了一个ProxyHandler类,这个ProxyHandler类实现了InvocationHandler接口,它充当事务处理器,比如类似于上面给汽车计时的日志处理,时间处理等事务都是在这个ProxyHandler类中完成的。
    InvocationHandler接口源码如下:

    package java.lang.reflect;
    public interface InvocationHandler {
        public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable;
    }

    其中第一个参数proxy代表代理对象;第二个参数method代表被代理的方法;第三个参数代表该方法的参数数组。

    JDK动态代理实现步骤:

    1. 创建一个实现InvocationHandler的类,必须实现invoke方法
    2. 创建被代理的类和接口
    3. 调用Proxy的静态方法,创建一个代理类
    4. 通过代理调用方法

    1,创建一个实现InvocationHandler的类,必须实现invoke方法:

    package com.jdkproxy;
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    public class TimeHandler implements InvocationHandler {
        private Object object;
        public TimeHandler(Object object) {
            super();
            //被代理的对象
            this.object = object;
        }
        /**
         * proxy: 代理对象
         * method: 被代理对象的方法
         * args:方法的参数
         * return:  调用方法的返回值
         */
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    
            long startTime = System.currentTimeMillis();
            System.out.println("汽车开始行驶");
    
            method.invoke(object);
    
            long endTime = System.currentTimeMillis();
            System.out.println("汽车行驶结束,行驶时间为:"+(endTime-startTime)+" ms");
            return null;
        }
    
    }
    

    步骤 2,3,4,以下为Test类:

    package com.jdkproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Proxy;
    
    import com.proxy.Car;
    import com.proxy.Moveable;
    
    public class Test {
    
        public static void main(String[]args){
            Car car = new Car();
            InvocationHandler h = new TimeHandler(car);
            Class<?> cls = car.getClass();
            /**
             * loader:类加载器
             * interfaces:实现的接口
             * h InvocationHandler
             */
            Moveable  m = (Moveable) Proxy.newProxyInstance(
                    cls.getClassLoader(), cls.getInterfaces(), h);
            m.move();
        }
    
    }

    运行结果:
    这里写图片描述

    CGLIB动态代理:
    CGLIB代理实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强。主要使用于改造遗留系统,这些系统一般不会继承特地的接口。

    cglib动态代理实现需要导入相关包,此处导入的为cglib-nodep-2.1_3.jar,然后需要创建事务处理器类,并实现MethodInterceptor接口,事务处理器类CglibProxy源码如下:

    package com.cjlibproxy;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class CglibProxy implements MethodInterceptor {
    
        private Enhancer enhancer = new Enhancer();
        public Object getProxy(Class clazz){
            //设置创建子类的类
            enhancer.setSuperclass(clazz);
            enhancer.setCallback(this);
            return enhancer.create();
        }
        /**
         * 拦截所有目标类方法的调用
         * obj 目标类的实例
         * m 目标方法的反射对象
         * args 方法的参数
         * proxy 代理类的实例
         */
        @Override
        public Object intercept(Object obj, Method m, Object[] args, 
                MethodProxy proxy) throws Throwable {
            //代理的业务逻辑
            System.out.println("代理:开车");
    
            //代理类调用父类的方法
            proxy.invokeSuper(obj, args);
    
            //代理的业务逻辑
            System.out.println("代理:到了");
            return null;
        }
    
    }
    

    有一个火车类,并没有实现接口:

    package com.cjlibproxy;
    
    public class Train {
        public void move(){
            System.out.println("火车行驶中...");
        }
    
    }
    

    测试类:

    package com.cjlibproxy;
    
    public class Test {
    
        public static void main(String[]args){
            CglibProxy proxy = new CglibProxy();
            Train t = (Train) proxy.getProxy(Train.class);
            t.move();
        }
    }
    

    测试结果:
    这里写图片描述

    总结: JDK动态代理和CGLIB动态代理的使用都很简单,如果能理解内部的具体实现流程才能更深刻的理解动态代理,关于JDK动态代理的模拟实现会在之后文章补充。

    标识类型模式

    定义一个不包含任何方法的接口,用它仅仅来表示一种抽象类型。所有实现该接口的类意味着属于这种类型。

    比如定义一个Food接口,其中不包含任何方法:

    public interface Food{}//实现该接口的类都是食物类型

    鱼肉:

    public class Fish implements Food{...}

    进食方法:

    public void eat(Food food){...}

    进食:

    Food fish = new Fish();//Fish实现了Food接口,标识其食物类型
    eat(fish);//合法
    Book book = new Book();//Book未实现Food接口
    eat(book);//编译错误

    所谓标识类型模式就是借助Java编译器来对传给eat()方法的food参数进行语义上的约束。Food接口被称为标识类型接口,这种接口没有任何方法,仅代表一种抽象类型。在JDK中,有如下两个典型的表示类型接口。

    • java.io.Serializable接口:实现该接口的类的实例可以被序列化
    • java.io.Remote接口:实现该接口的类的实例可以作为远程对象

    常量接口模式

    在一个软件系统中会使用一些常量,一种流行的做法是把相关的常量放在一个专门的常量接口中定义,例如:

    package com.FinalInterface;
    
    public interface MyConstants {
        public static final double MATH_PI = 3.1415926;
        public static final double MATH_E = 2.71828;
    
    }
    

    以下Circle类需要访问以上MATH_PI常量,一种方式是采用直接访问方式,如下:

    package com.FinalInterface;
    
    public class Circle {
        private double r;//半径
        public Circle(double r){
            this.r = r;
        }
        public double getCircumference(){
            return 2 * r * MyConstants.MATH_PI;
        }
    }
    

    在JDK1.5中引入了”import static“语句,它允许类A直接访问另一个接口B或类B中的静态常量,而不必指定接口B或类B的名字,而且类A无须实现接口B或者继承类B。如下:

    package com.FinalInterface;
    import static com.FinalInterface.MyConstants.*;
    public class Circle {
        private double r;//半径
        public Circle(double r){
            this.r = r;
        }
        public double getCircumference(){
            return 2 * r * MATH_PI;
        }
    }
    

    import static 语句既可以简化编程,又能防止Circle类继承并公开MyConstants中的静态常量。

    结合上我的上一篇:与接口相关的设计模式(1):定制服务模式和适配器模式详解,一共记录了与接口相关的5种设计模式,分别是定制服务模式、适配器模式、代理模式、标识类型模式以及常量接口模式。接口是构建松耦合的软件系统的重要法宝。接口的优势在于一个类可以实现多个接口,接口获得这一优势是以不允许为任何方法提供实现作为代价的(暂不考虑JAVA8的Default方法)。

    我们可以把接口作为系统中最高层次的抽象类型。站在外界使用者(另一个系统)的角度,接口向使用者承诺系统能提供哪些服务;站在系统本身的角度,接口指定系统必须实现哪些服务。系统之间通过接口进行交互,这可以提高系统之间的松耦合。

    至于抽象类呢,它用来定制系统中的扩展点。可以把抽象类看作介于”抽象“和”实现“之间的半成品。抽象类力所能及的完成了部分实现,但还有一些功能有待于它的子类去实现。

    展开全文
  • 面向接口编程的设计模式

    千次阅读 2017-03-13 13:18:53
    面向接口编程的设计模式简单工厂模式 假设程序中有个Computer类需要组合一个输出设备,现在有两个选择:直接让Computer类组合一个Printer,或者让Computer类组合一个Output,那么到底采用哪种方式更好呢? 假设让...

    面向接口编程的设计模式

    简单工厂模式

    • 假设程序中有个Computer类需要组合一个输出设备,现在有两个选择:直接让Computer类组合一个Printer,或者让Computer类组合一个Output,那么到底采用哪种方式更好呢?
    • 假设让Computer类组合一个Printer对象,如果有一天系统需要重构,需要使用BetterPrinter来代替Printer,这就需要打开
      Computer类源代码进行修改。如果系统中只有一个Computer类组合了Printer还好,但如果系统中有100个类组合了Printer,甚至
      1000个、10000个……将意味着需要打开100个、1000个、10000个类进行修改,工作量十分巨大。

    为了避免上面的问题发生,工厂模式建议让Computer类组合一个Output类型的对象,将Computer类与Printer类完全分离。Computer对象实际组合的是Printer对象还是BetterPrinter对象,对Computer而言完全透明。当Printer对象切换到BetterPrinter时,系统完全不受影响。代码如下:

    public class Computer {
        private Output out;
        public Computer(Output out) {
            this.out = out;
        }
        // 定义一个模拟获取字符串输入的方法
        public void keyIn(String msg) {
            out.getData(msg);
        }
        // 定义一个模拟打印的方法
        public void print() {
            out.out();
        }
    }
    • 上面的Computer类已经完全与Printer分离,只是与Output接口耦合。Computer不再负责创建Output对象,系统提供一个Output工厂来负责生成Output对象。这个OutputFactory工厂类代码如下:
    public class OutputFactory {
        public Output getOutput() {
            return new Printer();
        }
        public static void main(String[] args) {
            OutputFactory of = new OutputFactory();
            Computer c = new Computer(of.getOutput());
            c.keyIn("轻量级Java EE企业应用实战");
            c.keyIn("疯狂Java讲义");
            c.print();
        }
    }
    • 在该OutputFactory类中包含了一个getOutput方法,该方法负责创建Output实例并返回,如果系统需要将Printer改为BetterPrinter实现类,只需要让BetterPrinter实现Output接口,并改变OutputFactory类中的getOutput方法即可。

    下面是BetterPrinter实现类的代码,BetterPrinter只是对原有的Printer进行简单修改,以模拟系统重构后的改进。

    public class BetterPrinter implements Output {
        private String[] printData = new String[MAX_CACHE_LINE * 2];
        // 用以记录当前需打印的作业数
        private int dataNum = 0;
    
        public void out() {
            // 只要还有作业,继续打印
            while (dataNum > 0) {
                System.out.println("高速打印机正在打印:" + printData[0]);
                // 把作业队列整体前移一位,并将剩下的作业数减1
                System.arraycopy(printData, 1, printData, 0, --dataNum);
            }
        }
    
        public void getData(String msg) {
            if (dataNum >= MAX_CACHE_LINE * 2) {
                System.out.println("输出队列已满,添加失败");
            } else {
                // 把打印数据添加到队列里,已保存数据的数量加1。
                printData[dataNum++] = msg;
            }
        }
    }
    • 上面的BetterPrinter类也实现了Output接口,因此也可当成Output对象使用,于是只要把OutputFactory工厂类的getOutput方法修改即可。
    • 再次运行前面的OutputFactory程序,发现系统运行时已经改为BetterPrinter对象,而不再是原来的Printer对象。通过这种方式,即可把所有生成Output对象的逻辑集中在Output工厂类中管理,而所有需要使用Output对象的类只需与Output接口耦合,而不是与具体的实现类耦合。即是系统中有很多类使用了Printer对象,只要OutputFactory类的getOutput方法生的是BetterPrinter对象,则他们全部都会改为使用BetterPrinter对象,而所有程序无需修改每只需要修改OutputFactory工厂类的getOutput方法实现即可。

    命令模式

    某个方法需要完成某一个行为,但这个行为的具体实现无法确定,必须等到执行该方法时才可以确定。具体一点:假设有个方法需要遍历某个数组的数组元素,但无法确定在遍历时如何处理这些元素,需要在调用该方法时指定具体的处理行为。
    这个要求看起来有点奇怪:这个方法不仅需要普通数据可以变化,甚至还有方法执行提也需要变化,难道需要把“处理行为”作为参数传入该方法?
    对于这样一个需求,可以考虑使用一个Command接口来定义一个方法,用这个方法来封装“处理行为”。下面是Command接口的代码:

    public interface Command {
        // 接口里定义的process方法用于封装“处理行为”
        void process(int[] target);
    }

    上面的process方法没有方法体,因为还无法确定这个处理行为。
    下面是需要处理数组的处理类,在这个处理类中包含一个process方法,这个方法无法确定处理数组的处理行为,所以使用了一个Command参数,这个参数负责对数组的处理行为。

    public class ProcessArray {
        public void process(int[] target, Command cmd) {
            cmd.process(target);
        }
    }

    通过一个Command接口,就实现了让ProcessArray和具体处理行为的分离,程序使用Command接口代表类对数组的处理行为。Command接口也没有提供真正的处理,只有等待需要调用ProcessArray对象的process方法是,才真正传入一个Command对象,才确定对数组的处理行为。
    下面程序实现了对数组的两种处理方式:

    public class CommandTest {
        public static void main(String[] args) {
            ProcessArray pa = new ProcessArray();
            int[] target = { 3, -4, 6, 4 };
            // 第一次处理数组,具体处理行为取决于PrintCommand
            pa.process(target, new PrintCommand());
            System.out.println("------------------");
            // 第二次处理数组,具体处理行为取决于AddCommand
            pa.process(target, new AddCommand());
        }
    }
    
    public class PrintCommand implements Command {
        public void process(int[] target) {
            for (int tmp : target) {
                System.out.println("迭代输出目标数组的元素:" + tmp);
            }
        }
    }
    
    public class AddCommand implements Command {
        public void process(int[] target) {
            int sum = 0;
            for (int tmp : target) {
                sum += tmp;
            }
            System.out.println("数组元素的总和是:" + sum);
        }
    }
    展开全文
  • 接口及其设计模式

    千次阅读 2011-09-19 23:00:06
    1.接口有两种定义: ...关于接口设计模式: (1)定制服务模式:通过把每个服务都设为一个接口,这样可以粒度化每个服务。 如果需要某个特定的服务的组合,则只需要直接扩展细粒度的接口即可。 interface

    1.接口有两种定义:

    (1)对外的API.

    (2)interface的声明.


    关于接口的设计模式:

    (1)定制服务模式:通过把每个服务都设为一个接口,这样可以粒度化每个服务。

    如果需要某个特定的服务的组合,则只需要直接扩展细粒度的接口即可。

    interface InternetService{
    	public void connect();
    	public void disconnect();
    }
    interface MailService{
    	public void send();
    	public void receive();
    }
    interface VirusService{
    	public void begin();
    	public void end();
    }
    class InternetServiceImpl implements InternetService{
    	public void connect(){
    		System.out.println("开始连接网络..."); 
    	}
    	public void disconnect(){
    		System.out.println("开始关闭网络..."); 
    	}
    }
    class MailServiceImpl implements MailService{
    	public void send(){
    		System.out.println("开始发送邮件..."); 
    	}
    	public void receive(){
    		System.out.println("开始接收邮件..."); 
    	}
    }
    class VirusServiceImpl implements VirusService{
    	public void begin(){
    		System.out.println("开始检查病毒..."); 
    	}
    	public void end(){
    		System.out.println("检查病毒完毕..."); 
    	}
    }
    interface Menu1 extends InternetService,MailService{
    }
    interface Menu2 extends InternetService,VirusService{
    }
    class Menu1Impl implements Menu1{
    	private InternetService is;
    	private MailService ms;
    	public Menu1Impl(InternetService is,MailService ms){
    		this.is = is;
    		this.ms = ms;
    	}
    	public void connect(){
    		is.connect();
    	}
    	public void disconnect(){
    		is.disconnect();
    	}
    	public void send(){
    		ms.send();
    	}
    	public void receive(){
    		ms.receive();
    	}
    }
    class Menu2Impl implements Menu2{
    	private InternetService is;
    	private VirusService vs;
    	public Menu2Impl(InternetService is,VirusService vs){
    		this.is = is;
    		this.vs = vs;
    	}
    	public void connect(){
    		is.connect();
    	}
    	public void disconnect(){
    		is.disconnect();
    	}
    	public void begin(){
    		vs.begin();
    	}
    	public void end(){
    		vs.end();
    	}
    }
    public class ServiceDemo{
    	public static void main(String args[]){
    		InternetService is = new InternetServiceImpl();
    		MailService ms = new MailServiceImpl();
    		VirusService vs = new VirusServiceImpl();
    		Menu1Impl m1 = new Menu1Impl(is,ms);
    		Menu2Impl m2 = new Menu2Impl(is,vs);
    		System.out.println("检测menu1的功能中......"); 
    		m1.connect();
    		m1.disconnect();
    		m1.send();
    		m1.receive();
    		System.out.println("检测menu2的功能中......"); 
    		m2.connect();
    		m2.disconnect();
    		m2.begin();
    		m2.end();
    	}
    }

    2.适配器设计模式

    适配器是两个接口的中间过度,比如电脑必须要保证电压在15V,而电源的电压是220V,则需要一个适配器将220V转换成15V,因此适配器就是接口的转换作用。

    interface Source{
    	public int add(int a,int b);
    }
    class SourceImpl implements Source{
    	public int add(int a,int b){
    		return a+b;
    	}
    }
    interface Target{
    	public int addOne(int a);
    }
    class TargetImpl implements Target{
    	private Source s ;
    	public TargetImpl(Source s){
    		this.s = s;
    	}
    	public int addOne(int a){
    		return s.add(a,1);
    	}
    }
    public class AdapterDemo{
    	public static void main(String args[]){
    		Source s = new SourceImpl();
    		Target t = new TargetImpl(s);
    		System.out.println("2+1="+t.addOne(2));
    	}
    }

    3.默认适配器模式

    在java.awt.event包中,有许多接口,比如WindowEvent接口,比如此接口中有5个函数,如果要实现这个接口,必须要全部实现这些方法,如果我们只需要这个接口中的1个方法即可,但是其他的函数也必须实现,所以我们需要一个适配器,适配器中空实现接口,因此如果扩展适配器,则只要实现所需的方法即可。

    4.标识类型接口模式

    这个接口没有任何需要实现的方法,接口的意义只是标识作用,如果一个类实现了这个接口,只是说明这个类是某个类型的。

    比如Serializable接口就是典型的标识类型接口。

    5.常量接口模式

    在接口中只有public static final 常量。

    6.代理模式

    拥有委托类、代理类、第三方。

    注意:委托类和代理类实现同一个接口。

    代理类帮助委托类处理一些无用的或者轻易解决的问题。

    委托类是最终决定的类。

    interface A{
    	public boolean isAgree(int num);
    }
    class Source implements A{
    	private int deadLine = 1000;
    	public int getDeadLine(){
    		return deadLine;
    	}
    	public boolean isAgree(int num){
    		if(num>deadLine+100) return true;
    		else return false;
    	}
    }
    class Proxy implements A{
    	private Source s;
    	public Proxy(Source s){
    		this.s = s;	
    	}
    	public boolean isAgree(int num){
    		if(num<s.getDeadLine()){
    			return false;
    		}
    		return s.isAgree(num);
    	}
    }
    class Target{
    	private Proxy p;
    	public Target(Proxy p){
    		this.p = p;
    	}
    	public boolean isGet(int num){
    		return p.isAgree(num);
    	}
    }
    public class ProxyDemo{
    	public static void main(String args[]){
    		Source s = new Source();
    		Proxy p = new Proxy(s);
    		Target t = new Target(p);
    		System.out.println(t.isGet(800));
    		System.out.println(t.isGet(1200)); 
    	}
    }


    展开全文
  • java中接口和工厂设计模式

    千次阅读 2018-03-06 17:55:13
    什么接口? 接口是一种特殊的抽象类,接口中只有抽象方法和全局变量,且没有构造函数。接口的特点有:Java接口中只能包含public,static,final类型的成员变量(默认都是public,static,final类型的,因此在写的时候...

    一.什么是接口?

     接口是一种特殊的抽象类,接口中只有抽象方法和全局变量,且没有构造函数。

    接口的特点有:

    1. Java接口中只能包含public,static,final类型的成员变量(默认都是public,static,final类型的,因此在写的时候可以省略)和public,abstract类型的成员方法(默认都是public,abstract类型的,因此在写的时候可以省略);
    2. 接口中没有构造方法,不能被实例化,接口的对象可以利用子类对象的向上转型进行实例化;
    3. 一个接口不能实现(implements)另一个接口,但它可以继承多个其它的接口(接口可以多继承);
    4. 接口必须要有子类,但此时一个子类可以使用implements关键字实现多个接口,当类实现了某个Java接口时,它必须实现接口中的所有抽象方法,否则这个类必须声明为抽象类;

    二.接口的应用。

    定义一个接口Person,以及他的两个实现子类Programmer(程序员)和Pm(产品经理);

    设计一个工厂类Factory,当需要增加更多的子类的时候只需要在Factory中修改方法即可。

    Person接口:

    package test;
    public interface Person {
    
    
    	public static final String type="员工";
    	String sex="男";
    	
    	public abstract void work();
    	public abstract void recreation();
    
    }

    工厂类,来对应出具体的子类:

    package test;
    public class Factory {
       public static Person getType(String className){
    	   if(className.equals("Programmer")){
    		   return new Programmer();
    	   }
    	   if(className.equals("Pm")){
    		   return new Pm();
    	   }
    	   return null;
       }
    
    }

    Programmer类实现了Person接口:

    package test;
    public class Programmer implements Person{
    
    
    	public void recreation() {
    		System.out.println("我的娱乐活动就是看书");
    		
    	}
    
    
    	public void work() {
    		System.out.println("写代码,调试bug");
    	}
    
    }

    Pm类实现了Person接口:

    package test;
    public class Pm implements Person {
    
    
    	public void recreation() {
    		System.out.println("我的娱乐活动是关注实时的互联网动态");
    	}
    
    
    	public void work() {
    		System.out.println("整理需求,沟通客户");
    	}
    }

    定义一个主类,实现不同人员的不同表现形态:

    package test;
    public class MainClass {
    	public static void main(String[] args){
    		Person p1=Factory.getType("Programmer");
    		p1.work();
    		p1.recreation();
    		Person p2=Factory.getType("Pm");
    		p2.work();
    		p2.recreation();
    	}
    
    }

    输出结果:

    写代码,调试bug
    我的娱乐活动就是看书
    整理需求,沟通客户
    我的娱乐活动是关注实时的互联网动态

    展开全文
  • 设计模式 - 结构型设计模式 - 代理模式(Java)

    万次阅读 多人点赞 2019-02-02 16:23:28
    分享一个大牛的人工智能教程。零基础!通俗易懂!风趣幽默!希望你也加入到人工智能的队伍中来!...另一种是我们自己没有定义接口,Spring 会采用 CGLIB 进行动态代理,它是一个 jar 包,性能还不错。
  • 一、 模板设计模式 ** 开闭原则(OCP):一个软件实体如类、模块和函数应该对外扩展开放、对修改关闭; 开闭原则是java世界中最基础的设计原则**。 概述 模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以...
  • 设计模式 - 行为型设计模式 - 策略模式(Java)

    万次阅读 多人点赞 2019-02-27 10:38:14
    首先,先定义一个策略接口: public interface Strategy { public void draw(int radius, int x, int y); } 然后我们定义具体的几个策略: public class RedPen implements Strategy { @Override public void draw...
  • 设计模式 - 结构型设计模式 - 适配器模式(Java)

    万次阅读 多人点赞 2019-01-23 20:24:55
    对象适配器模式 来看一个《Head First 设计模式》中的一个例子,我们稍微修改了一下,看看怎么将鸡适配成鸭,这样鸡也能当鸭来用。因为,现在鸭这个接口我们没有合适的实现类可以用,所以需要适配器。 public ...
  • Java中的设计模式 - 适配器模式(接口适配器)应用场景:不想实现接口中的所有方法#1 - 创建接口/** * Created by 谭健 2017年7月2日 20:56:08 * 定义端口接口,提供通信服务 */ public interface Port { // 远程...
  • Java接口设计模式

    千次阅读 2014-03-30 17:26:52
    Java接口设计模式 java设计模式编程语言工具oop java不允许多重继承,也就是说一个子类只能有一个父类,Son extends FatherA,FatherB 是错误的为了弥补这点不足,java允许实现多个接口, 接口就是给出一些没有...
  • 常用设计模式总结

    万次阅读 多人点赞 2019-07-31 19:13:12
    设计模式(Design pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,是可复用面向对象软件的基础。使用设计模式是为了可重用代码、让代码更容易被他人理解、保证代码可靠性。 ...
  • 接口模式四种使用场景 适配器模式 外观模式 合成模式 桥接模式接口与抽象类区别 继承个数 抽象方法 字段定义 方法描述 构造器; ③ 桩的使用, 使实现类能间接实现自己感兴趣的方法;
  • 设计模式 - 行为型设计模式 - 观察者模式(Java)

    万次阅读 多人点赞 2019-02-12 14:59:26
    } 其实如果只有一个观察者类的话,接口都不用定义了,不过,通常场景下,既然用到了观察者模式我们就是希望一个事件出来了,会有多个不同的类需要处理相应的信息。比如,订单修改成功事件,我们希望发短信的类...
  • 设计模式 - 创建型设计模式 - 原型模式(Java)

    万次阅读 多人点赞 2019-02-19 19:51:19
    当然,如果我们要调用这个方法,Java 要求我们的类必须先实现 Cloneable 接口,此接口没有定义任何方法,但是不这么做的话,在 clone() 的时候,会抛出 CloneNotSupportedException 异常。 protected native Object ...
  • 设计模式 - 行为型设计模式 - 状态模式(Java)

    万次阅读 多人点赞 2019-02-12 15:38:33
    商品库存中心有个最基本的需求是减库存和补库存,我们看看怎么用状态模式来写。 核心在于,我们的关注点不再是 Context 是该进行哪种操作,而是关注这个 Context 会有哪些操作。 定义状态接口: public interface ...
  • 23种设计模式汇总整理

    万次阅读 多人点赞 2015-04-09 10:57:11
    设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式 结构型模式,共七种:适配器模式、装饰者模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 ...
  • Java设计模式-接口隔离原则

    千次阅读 2019-03-11 08:40:15
      定义1:客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上(Clients should not be forced to depend upon interfaces that they don’t use.)。   定义2:类间的依赖关系应该...
  • 在.NET平台上,数据绑定是一项令人十分愉快的技术。利用数据绑定能减少代码,简化控制逻辑。 通常,可以将某个对象的一个属性...此接口定义了 PropertyChanged 事件,我们只需在属性值改变时触发该事件即可.INotifyP
  • 记录学习设计模式的过程 #单一职责原则 概念 定义:不要存在多于一个导致类变更的原因 一个类、接口、方法只负责一项职责 优点:、、 案例 单一职责原则很简单,一个方法 一个类只负责一个职责,各个职责的程序...
  • 设计模式

    千次阅读 多人点赞 2019-07-22 09:33:22
    设计模式简介 设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过...
  • 不管我们以前用的对还是不对,这一次我们还是对以前在项目中用到过的设计模式更加的熟悉,所以总结一句话,我们在平常的编码过程中应该多用一些设计模式,这样我们才能更好的理解设计模式的精髓。
  • -- 问题解决场景 : 在 类A 中实现了接口中的抽象方法, 客户端B 已经定义好了方法的调用, 但是调用的方法 与 类A 中的方法名不同, 这时我们就需要适配器模式了; -- eg : 类A 实现了接口A1, 类B 实现了接口B1, ...
  • 大话设计模式这本书写的非常有创意,非常适合我这种新手。...现在只想着写点什么用上它几种设计模式。  可能是第一次接触这些东西,有些感觉看懂了,但是很难应用到实际编程中;有些感觉没看懂,但
  • 设计模式个人总结,接口隔离原则总结。近期自学Unity引擎,学到了关于设计模式这一块,以前学习Java多次接触设计模式,也在应用的开发过程中频繁使用。虽然开发过程中没有特意去强调使用设计模式,但设计模式的使用...
  • 依赖倒置原则和接口隔离原则的记录。 依赖倒置原则:高层模块不应该依赖低层模块,两者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象; 接口隔离原则:建立单一接口,不要建立臃肿庞大的接口
  • 设计模式 - 策略模式

    千次阅读 2019-08-22 17:53:02
    文章目录设计模式 - 策略模式1、意图2、实例1、创建算法策略接口2、定义加法3、定义减法4、定义策略上下文5、使用策略进行计算 设计模式 - 策略模式 1、意图 定义一系列算法,封装每个算法,并使它们可以互换。 ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 565,266
精华内容 226,106
关键字:

我们定义的接口属于什么设计模式