精华内容
下载资源
问答
  • 说到代理,大家肯定都...下面我们就java中的两种代理模式进行讲解。1.静态代理由程序员创建或者由第三方工具生成,再进行编译;在程序运行之前,代理类的.class文件已经存在了。静态代理通常只代理一个类,并且...

    97443af696eab5bf3a2fe3d94a8b468c.png

    说到代理,大家肯定都有接触过。毕竟当有些事务不想亲自处理时,会选择委托给别人进行解决。那么在java中也有着这样的机制,叫做代理模式。主要分为两大类:静态代理和动态代理。一种是运行前就存在,另一种是运行后才进行创建。下面我们就java中的两种代理模式进行讲解。

    1.静态代理

    由程序员创建或者由第三方工具生成,再进行编译;在程序运行之前,代理类的.class文件已经存在了。静态代理通常只代理一个类,并且要事先知道代理的是什么。public class BlogStaticProxy implements IBlogService{

    private IBlogService blogService;

    public BlogStaticProxy(IBlogService blogService) {

    this.blogService = blogService;

    }

    @Override

    public void writeBlog() {

    System.out.println("start writing...");

    blogService.writeBlog();

    System.out.println("end writing...");

    }

    }

    2.动态代理

    动态代理的代理类在程序运行前是不存在的,也就是说代理类在程序运行时才创建的代理模式成为动态代理。这种情况下,代理类并不是在Java代码中定义好的,而是在程序运行时根据我们的在Java代码中的“指示”动态生成的。public class MainClass {

    public static void main(String[] args) {

    //1、创建一个真实角色

    Singer target = new Singer();

    //2、调用Proxy.newProxyInstance方法,并构造一个InvocationHandler对象,

    //3、在对象内部重写invoke方法,同时调用method.invoke(target,args);

    //4、并在该方法的上下添加自己的代码逻辑

    //其中:target.getClass().getClassLoader():获取类加载器,用来生成代理对象;

    //   target.getClass().getInterfaces()获取接口元信息;

    ISinger iSinger = (ISinger) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {

    @Override

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

    System.out.println("动态代理---向观众问好");//在真实对象的方法被调用“前”编写自己的业务逻辑

    Object returnValue = method.invoke(target,args);//此处通过反射调用真实对象对应的方法;

    System.out.println("动态代理---向观众问好");//在真实对象的方法被调用“后”编写自己的业务逻辑

    return returnValue;

    }

    });

    iSinger.sing();

    }

    }

    //测试结果

    "C:\Program Files\Java\jdk1.8.0_211\bin\java.exe" "-javaagent:C:\Program.......

    动态代理---向观众问好

    sing a song

    动态代理---向观众问好

    Process finished with exit code 0

    以上就是java代理模式的分类,学习完本篇的内容后,想必大家已经能对静态代理和动态代理有所区分。在实际使用时,可以根据需求自行选择。

    展开全文
  • Java几种常用设计模式

    万次阅读 多人点赞 2018-08-09 16:50:32
    Java 中一般认为23种设计模式,当然暂时不需要所有的都会,但是其中常见的几种设计模式应该去掌握。 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、...

    Java 中一般认为有23种设计模式,当然暂时不需要所有的都会,但是其中常见的几种设计模式应该去掌握。
    总体来说设计模式分为三大类:
    创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
    结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
    行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

    1. 单例模式

    所谓的单例设计指的是一个类只允许产生一个实例化对象。
    最好理解的一种设计模式,分为懒汉式和饿汉式。

    饿汉式:构造方法私有化,外部无法产生新的实例化对象,只能通过static方法取得实例化对象

    class Singleton {
        /**
         * 在类的内部可以访问私有结构,所以可以在类的内部产生实例化对象
         */
        private static Singleton instance = new Singleton();
        /**
         * private 声明构造
         */
        private Singleton() {
    
        }
        /**
         * 返回对象实例
         */
        public static Singleton getInstance() {
            return instance;
        }
    
        public void print() {
            System.out.println("Hello Singleton...");
        }
    }

    懒汉式:当第一次去使用Singleton对象的时候才会为其产生实例化对象的操作

    class Singleton {
    
        /**
         * 声明变量
         */
        private static volatile Singleton singleton = null;
    
        /**
         * 私有构造方法
         */
        private Singleton() {
    
        }
    
        /**
         * 提供对外方法
         * @return 
         */
        public static Singleton getInstance() {
            // 还未实例化
            if (singleton == null) {
                synchronized (Singleton.class) {
                    if (singleton == null) {
                        singleton = new Singleton();
                    }
                }
            }
            return singleton;
        }
        public void print() {
            System.out.println("Hello World");
        }
    }

    当多个线程并发执行 getInstance 方法时,懒汉式会存在线程安全问题,所以用到了 synchronized 来实现线程的同步,当一个线程获得锁的时候其他线程就只能在外等待其执行完毕。而饿汉式则不存在线程安全的问题。

    2. 工厂设计模式

    工厂模式分为工厂方法模式和抽象工厂模式。

    工厂方法模式

    工厂方法模式:
    1. 工厂方法模式分为三种:普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
    2. 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
    3. 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

    1. 普通工厂模式

    建立一个工厂类,对实现了同一接口的一些类进行实例的创建。

    interface Sender {
        void Send();
    }
    
    class MailSender implements Sender {
    
        @Override
        public void Send() {
            System.out.println("This is mail sender...");
        }
    }
    
    class SmsSender implements Sender {
    
        @Override
        public void Send() {
            System.out.println("This is sms sender...");
        }
    }
    
    public class FactoryPattern {
        public static void main(String[] args) {
            Sender sender = produce("mail");
            sender.Send();
        }
        public static Sender produce(String str) {
            if ("mail".equals(str)) {
                return new MailSender();
            } else if ("sms".equals(str)) {
                return new SmsSender();
            } else {
                System.out.println("输入错误...");
                return null;
            }
        }
    }

    2. 多个工厂方法模式

    该模式是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。

    interface Sender {
        void Send();
    }
    
    class MailSender implements Sender {
    
        @Override
        public void Send() {
            System.out.println("This is mail sender...");
        }
    }
    
    class SmsSender implements Sender {
    
        @Override
        public void Send() {
            System.out.println("This is sms sender...");
        }
    }
    
    class SendFactory {
        public Sender produceMail() {
            return new MailSender();
        }
    
        public Sender produceSms() {
            return new SmsSender();
        }
    }
    
    public class FactoryPattern {
        public static void main(String[] args) {
            SendFactory factory = new SendFactory();
            Sender sender = factory.produceMail();
            sender.Send();
        }
    }

    3. 静态工厂方法模式

    将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

    interface Sender {
        void Send();
    }
    
    class MailSender implements Sender {
    
        @Override
        public void Send() {
            System.out.println("This is mail sender...");
        }
    }
    
    class SmsSender implements Sender {
    
        @Override
        public void Send() {
            System.out.println("This is sms sender...");
        }
    }
    
    class SendFactory {
        public static Sender produceMail() {
            return new MailSender();
        }
    
        public static Sender produceSms() {
            return new SmsSender();
        }
    }
    
    public class FactoryPattern {
        public static void main(String[] args) {
            Sender sender = SendFactory.produceMail();
            sender.Send();
        }
    }

    抽象工厂模式

    工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要扩展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?
    那么这就用到了抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

    interface Provider {
        Sender produce();
    }
    
    interface Sender {
        void Send();
    }
    
    class MailSender implements Sender {
    
        public void Send() {
            System.out.println("This is mail sender...");
        }
    }
    
    class SmsSender implements Sender {
    
        public void Send() {
            System.out.println("This is sms sender...");
        }
    }
    
    class SendMailFactory implements Provider {
    
        public Sender produce() {
            return new MailSender();
        }
    }
    
    class SendSmsFactory implements Provider {
    
        public Sender produce() {
            return new SmsSender();
        }
    }
    
    
    public class FactoryPattern {
        public static void main(String[] args) {
            Provider provider = new SendMailFactory();
            Sender sender = provider.produce();
            sender.Send();
        }
    }

    3. 建造者模式

    工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性。

    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @Author: LiuWang
     * @Created: 2018/8/6 17:47
     */
    
    abstract class Builder {
        /**
         * 第一步:装CPU
         */
       public abstract void buildCPU();
    
        /**
         * 第二步:装主板
         */
        public abstract void buildMainBoard();
    
        /**
         * 第三步:装硬盘
         */
        public abstract void buildHD();
    
        /**
         * 获得组装好的电脑
         * @return
         */
        public abstract Computer getComputer();
    }
    
    /**
     * 装机人员装机
     */
    class Director {
        public void Construct(Builder builder) {
            builder.buildCPU();
            builder.buildMainBoard();
            builder.buildHD();
        }
    }
    
    /**
     * 具体的装机人员
     */
    class ConcreteBuilder extends  Builder {
    
        Computer computer = new Computer();
    
        @Override
        public void buildCPU() {
            computer.Add("装CPU");
        }
    
        @Override
        public void buildMainBoard() {
            computer.Add("装主板");
        }
    
        @Override
        public void buildHD() {
            computer.Add("装硬盘");
        }
    
        @Override
        public Computer getComputer() {
            return computer;
        }
    }
    
    class Computer {
    
        /**
         * 电脑组件集合
         */
        private List<String> parts = new ArrayList<String>();
    
        public void Add(String part) {
            parts.add(part);
        }
    
        public void print() {
            for (int i = 0; i < parts.size(); i++) {
                System.out.println("组件:" + parts.get(i) + "装好了...");
            }
            System.out.println("电脑组装完毕...");
        }
    }
    
    public class BuilderPattern {
    
        public static void main(String[] args) {
            Director director = new Director();
            Builder builder = new ConcreteBuilder();
            director.Construct(builder);
            Computer computer = builder.getComputer();
            computer.print();
        }
    }

    4. 适配器设计模式

    适配器模式是将某个类的接口转换成客户端期望的另一个接口表示,目的是消除由于接口不匹配所造成的的类的兼容性问题。主要分三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

    1. 类的适配器模式:

    class Source {
        public void method1() {
            System.out.println("This is original method...");
        }
    }
    
    interface Targetable {
    
        /**
         * 与原类中的方法相同
         */
        public void method1();
    
        /**
         * 新类的方法
         */
        public void method2();
    }
    
    class Adapter extends Source implements Targetable {
    
        @Override
        public void method2() {
            System.out.println("This is the targetable method...");
        }
    }
    
    public class AdapterPattern {
        public static void main(String[] args) {
            Targetable targetable = new Adapter();
            targetable.method1();
            targetable.method2();
        }
    }

    2. 对象的适配器模式

    基本思路和类的适配器模式相同,只是将Adapter 类作修改,这次不继承Source 类,而是持有Source 类的实例,以达到解决兼容性的问题。

    class Source {
        public void method1() {
            System.out.println("This is original method...");
        }
    }
    
    interface Targetable {
    
        /**
         * 与原类中的方法相同
         */
        public void method1();
    
        /**
         * 新类的方法
         */
        public void method2();
    }
    
    class Wrapper implements Targetable {
    
        private Source source;
    
        public Wrapper(Source source) {
            super();
            this.source = source;
        }
    
        @Override
        public void method1() {
            source.method1();
        }
    
        @Override
        public void method2() {
            System.out.println("This is the targetable method...");
        }
    }
    
    public class AdapterPattern {
        public static void main(String[] args) {
            Source source = new Source();
            Targetable targetable = new Wrapper(source);
            targetable.method1();
            targetable.method2();
        }
    }

    3. 接口的适配器模式

    接口的适配器是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

    /**
     * 定义端口接口,提供通信服务
     */
    interface Port {
        /**
         * 远程SSH端口为22
         */
        void SSH();
    
        /**
         * 网络端口为80
         */
        void NET();
    
        /**
         * Tomcat容器端口为8080
         */
        void Tomcat();
    
        /**
         * MySQL数据库端口为3306
         */
        void MySQL();
    }
    
    /**
     * 定义抽象类实现端口接口,但是什么事情都不做
     */
    abstract class Wrapper implements Port {
        @Override
        public void SSH() {
    
        }
    
        @Override
        public void NET() {
    
        }
    
        @Override
        public void Tomcat() {
    
        }
    
        @Override
        public void MySQL() {
    
        }
    }
    
    /**
     * 提供聊天服务
     * 需要网络功能
     */
    class Chat extends Wrapper {
        @Override
        public void NET() {
            System.out.println("Hello World...");
        }
    }
    
    /**
     * 网站服务器
     * 需要Tomcat容器,Mysql数据库,网络服务,远程服务
     */
    class Server extends Wrapper {
        @Override
        public void SSH() {
            System.out.println("Connect success...");
        }
    
        @Override
        public void NET() {
            System.out.println("WWW...");
        }
    
        @Override
        public void Tomcat() {
            System.out.println("Tomcat is running...");
        }
    
        @Override
        public void MySQL() {
            System.out.println("MySQL is running...");
        }
    }
    
    public class AdapterPattern {
    
        private static Port chatPort = new Chat();
        private static Port serverPort = new Server();
    
        public static void main(String[] args) {
            // 聊天服务
            chatPort.NET();
    
            // 服务器
            serverPort.SSH();
            serverPort.NET();
            serverPort.Tomcat();
            serverPort.MySQL();
        }
    }

    5. 装饰模式

    顾名思义,装饰模式就是给一个对象增加一些新的功能,而且是动态的,要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例。

    interface Shape {
        void draw();
    }
    
    /**
     * 实现接口的实体类
     */
    class Rectangle implements Shape {
    
        @Override
        public void draw() {
            System.out.println("Shape: Rectangle...");
        }
    }
    
    class Circle implements Shape {
    
        @Override
        public void draw() {
            System.out.println("Shape: Circle...");
        }
    }
    
    /**
     * 创建实现了 Shape 接口的抽象装饰类。
     */
    abstract class ShapeDecorator implements Shape {
        protected Shape decoratedShape;
    
        public ShapeDecorator(Shape decoratedShape) {
            this.decoratedShape = decoratedShape;
        }
    
        @Override
        public void draw() {
            decoratedShape.draw();
        }
    }
    
    /**
     *  创建扩展自 ShapeDecorator 类的实体装饰类。
     */
    class RedShapeDecorator extends ShapeDecorator {
    
        public RedShapeDecorator(Shape decoratedShape) {
            super(decoratedShape);
        }
    
        @Override
        public void draw() {
            decoratedShape.draw();
            setRedBorder(decoratedShape);
        }
    
        private void setRedBorder(Shape decoratedShape) {
            System.out.println("Border Color: Red");
        }
    }
    
    /**
     * 使用 RedShapeDecorator 来装饰 Shape 对象。
     */
    public class DecoratorPattern {
        public static void main(String[] args) {
            Shape circle = new Circle();
            Shape redCircle = new RedShapeDecorator(new Circle());
            Shape redRectangle = new RedShapeDecorator(new Rectangle());
            System.out.println("Circle with normal border");
            circle.draw();
    
            System.out.println("\nCircle of red border");
            redCircle.draw();
    
            System.out.println("\nRectangle of red border");
            redRectangle.draw();
        }
    }

    6. 策略模式

    策略模式定义了一系列算法,并将每个算法封装起来,使他们可以相互替换,且算法的变化不会影响到使用算法的客户。需要设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口,设计一个抽象类(可有可无,属于辅助类),提供辅助函数。策略模式的决定权在用户,系统本身提供不同算法的实现,新增或者删除算法,对各种算法做封装。因此,策略模式多用在算法决策系统中,外部用户只需要决定用哪个算法即可。

    /**
     * 抽象算法的策略类,定义所有支持的算法的公共接口
     */
    abstract class Strategy {
        /**
         * 算法方法
         */
        public abstract void AlgorithmInterface();
    }
    
    /**
     * 具体算法A
     */
    class ConcreteStrategyA extends Strategy {
        //算法A实现方法
        @Override
        public void AlgorithmInterface() {
            System.out.println("算法A的实现");
        }
    }
    
    /**
     * 具体算法B
     */
    class ConcreteStrategyB extends Strategy {
        /**
         * 算法B实现方法
         */
        @Override
        public void AlgorithmInterface() {
            System.out.println("算法B的实现");
        }
    }
    
    /**
     * 具体算法C
     */
    class ConcreteStrategyC extends Strategy {
        @Override
        public void AlgorithmInterface() {
            System.out.println("算法C的实现");
        }
    }
    
    /**
     * 上下文,维护一个对策略类对象的引用
     */
    class Context {
        Strategy strategy;
    
        public Context(Strategy strategy) {
            this.strategy = strategy;
        }
    
        public void contextInterface(){
            strategy.AlgorithmInterface();
        }
    }
    
    /**
     * 客户端代码:实现不同的策略
     */
    public class StrategyPattern {
        public static void main(String[] args) {
    
            Context context;
    
            context = new Context(new ConcreteStrategyA());
            context.contextInterface();
    
            context = new Context(new ConcreteStrategyB());
            context.contextInterface();
    
            context = new Context(new ConcreteStrategyC());
            context.contextInterface();
        }
    }

    7. 代理模式

    代理模式指给一个对象提供一个代理对象,并由代理对象控制对原对象的引用。代理可以分为静态代理和动态代理。
    通过代理模式,可以利用代理对象为被代理对象添加额外的功能,以此来拓展被代理对象的功能。可以用于计算某个方法执行时间,在某个方法执行前后记录日志等操作。

    1. 静态代理

    静态代理需要我们写出代理类和被代理类,而且一个代理类和一个被代理类一一对应。代理类和被代理类需要实现同一个接口,通过聚合使得代理对象中有被代理对象的引用,以此实现代理对象控制被代理对象的目的。

    /**
     * 代理类和被代理类共同实现的接口
     */
    interface IService {
    
        void service();
    }
    
    
    /**
     * 被代理类
     */
    class Service implements IService{
    
        @Override
        public void service() {
            System.out.println("被代理对象执行相关操作");
        }
    }
    
    /**
     * 代理类
     */
    class ProxyService implements IService{
        /**
         * 持有被代理对象的引用
         */
        private IService service;
    
        /**
         * 默认代理Service类
         */
        public ProxyService() {
            this.service = new Service();
        }
    
        /**
         * 也可以代理实现相同接口的其他类
         * @param service
         */
        public ProxyService(IService service) {
            this.service = service;
        }
    
        @Override
        public void service() {
            System.out.println("开始执行service()方法");
            service.service();
            System.out.println("service()方法执行完毕");
        }
    }
    
    
    //测试类
    public class ProxyPattern {
    
        public static void main(String[] args) {
            IService service = new Service();
            //传入被代理类的对象
            ProxyService proxyService = new ProxyService(service);
            proxyService.service();
        }
    }

    2. 动态代理

    JDK 1.3 之后,Java通过java.lang.reflect包中的三个类Proxy、InvocationHandler、Method来支持动态代理。动态代理常用于有若干个被代理的对象,且为每个被代理对象添加的功能是相同的(例如在每个方法运行前后记录日志)。

    动态代理的代理类不需要我们编写,由Java自动产生代理类源代码并进行编译最后生成代理对象。
    创建动态代理对象的步骤:
    1. 指明一系列的接口来创建一个代理对象
    2. 创建一个调用处理器(InvocationHandler)对象
    3. 将这个代理指定为某个其他对象的代理对象
    4. 在调用处理器的invoke()方法中采取代理,一方面将调用传递给真实对象,另一方面执行各种需要的操作

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    /**
     * 代理类和被代理类共同实现的接口
     */
    interface IService {
        void service();
    }
    
    class Service implements IService{
    
        @Override
        public void service() {
            System.out.println("被代理对象执行相关操作");
        }
    }
    
    class ServiceInvocationHandler implements InvocationHandler {
    
        /**
         * 被代理的对象
         */
        private Object srcObject;
    
        public ServiceInvocationHandler(Object srcObject) {
            this.srcObject = srcObject;
        }
    
        @Override
        public Object invoke(Object proxyObj, Method method, Object[] args) throws Throwable {
            System.out.println("开始执行"+method.getName()+"方法");
            //执行原对象的相关操作,容易忘记
            Object returnObj = method.invoke(srcObject,args);
            System.out.println(method.getName()+"方法执行完毕");
            return returnObj;
        }
    }
    
    public class ProxyPattern {
        public static void main(String[] args) {
            IService service = new Service();
            Class<? extends IService> clazz = service.getClass();
    
            IService proxyService = (IService) Proxy.newProxyInstance(clazz.getClassLoader(),
                                            clazz.getInterfaces(), new ServiceInvocationHandler(service));
            proxyService.service();
        }
    }
    展开全文
  • 面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问“茴香豆的茴字有哪几种写法?” 所谓代理模式,是指客户端(Client)并不直接调用实际的对象(下图右下角的...

    面试问题:Java里的代理设计模式(Proxy Design Pattern)一共有几种实现方式?这个题目很像孔乙己问“茴香豆的茴字有哪几种写法?”

    所谓代理模式,是指客户端(Client)并不直接调用实际的对象(下图右下角的RealSubject),而是通过调用代理(Proxy),来间接的调用实际的对象。

    代理模式的使用场合,一般是由于客户端不想直接访问实际对象,或者访问实际的对象存在技术上的障碍,因而通过代理对象作为桥梁,来完成间接访问。

    实现方式一:静态代理

    开发一个接口IDeveloper,该接口包含一个方法writeCode,写代码。

    public interface IDeveloper {
    
         public void writeCode();
    
    }

    创建一个Developer类,实现该接口。

    public class Developer implements IDeveloper{
        private String name;
        public Developer(String name){
            this.name = name;
        }
        @Override
        public void writeCode() {
            System.out.println("Developer " + name + " writes code");
        }
    }

    测试代码:创建一个Developer实例,名叫Jerry,去写代码!

    public class DeveloperTest {
        public static void main(String[] args) {
            IDeveloper jerry = new Developer("Jerry");
            jerry.writeCode();
        }
    }

    现在问题来了。Jerry的项目经理对Jerry光写代码,而不维护任何的文档很不满。假设哪天Jerry休假去了,其他的程序员来接替Jerry的工作,对着陌生的代码一脸问号。经全组讨论决定,每个开发人员写代码时,必须同步更新文档。

    为了强迫每个程序员在开发时记着写文档,而又不影响大家写代码这个动作本身, 我们不修改原来的Developer类,而是创建了一个新的类,同样实现IDeveloper接口。这个新类DeveloperProxy内部维护了一个成员变量,指向原始的IDeveloper实例:

    public class DeveloperProxy implements IDeveloper{
        private IDeveloper developer;
        public DeveloperProxy(IDeveloper developer){
            this.developer = developer;
        }
        @Override
        public void writeCode() {
            System.out.println("Write documentation...");
            this.developer.writeCode();
        }
    }

    这个代理类实现的writeCode方法里,在调用实际程序员writeCode方法之前,加上一个写文档的调用,这样就确保了程序员写代码时都伴随着文档更新。

    测试代码:

    静态代理方式的优点

    1. 易于理解和实现

    2. 代理类和真实类的关系是编译期静态决定的,和下文马上要介绍的动态代理比较起来,执行时没有任何额外开销。

    静态代理方式的缺点

    每一个真实类都需要一个创建新的代理类。还是以上述文档更新为例,假设老板对测试工程师也提出了新的要求,让测试工程师每次测出bug时,也要及时更新对应的测试文档。那么采用静态代理的方式,测试工程师的实现类ITester也得创建一个对应的ITesterProxy类。

    public interface ITester {
        public void doTesting();
    }
    Original tester implementation class:
    public class Tester implements ITester {
        private String name;
        public Tester(String name){
            this.name = name;
        }
        @Override
        public void doTesting() {
            System.out.println("Tester " + name + " is testing code");
        }
    }
    public class TesterProxy implements ITester{
        private ITester tester;
        public TesterProxy(ITester tester){
            this.tester = tester;
        }
        @Override
        public void doTesting() {
            System.out.println("Tester is preparing test documentation...");
            tester.doTesting();
        }
    }

    正是因为有了静态代码方式的这个缺点,才诞生了Java的动态代理实现方式。

    Java动态代理实现方式一:InvocationHandler

    InvocationHandler的原理我曾经专门写文章介绍过:Java动态代理之InvocationHandler最简单的入门教程

    通过InvocationHandler, 我可以用一个EnginnerProxy代理类来同时代理Developer和Tester的行为。

    public class EnginnerProxy implements InvocationHandler {
        Object obj;
        public Object bind(Object obj)
        {
            this.obj = obj;
            return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
            .getClass().getInterfaces(), this);
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable
        {
            System.out.println("Enginner writes document");
            Object res = method.invoke(obj, args);
            return res;
        }
    }

    真实类的writeCode和doTesting方法在动态代理类里通过反射的方式进行执行。

    测试输出:

    通过InvocationHandler实现动态代理的局限性

    假设有个产品经理类(ProductOwner) 没有实现任何接口。

    public class ProductOwner {
        private String name;
        public ProductOwner(String name){
            this.name = name;
        }
        public void defineBackLog(){
            System.out.println("PO: " + name + " defines Backlog.");
        }
    }

    我们仍然采取EnginnerProxy代理类去代理它,编译时不会出错。运行时会发生什么事?

    ProductOwner po = new ProductOwner("Ross");
    
    ProductOwner poProxy = (ProductOwner) new EnginnerProxy().bind(po);
    
    poProxy.defineBackLog();

    运行时报错。所以局限性就是:如果被代理的类未实现任何接口,那么不能采用通过InvocationHandler动态代理的方式去代理它的行为。

    Java动态代理实现方式二:CGLIB

    CGLIB是一个Java字节码生成库,提供了易用的API对Java字节码进行创建和修改。关于这个开源库的更多细节,请移步至CGLIB在github上的仓库:https://github.com/cglib/cglib

    我们现在尝试用CGLIB来代理之前采用InvocationHandler没有成功代理的ProductOwner类(该类未实现任何接口)。

    现在我改为使用CGLIB API来创建代理类:

    public class EnginnerCGLibProxy {
        Object obj;
        public Object bind(final Object target)
        {
            this.obj = target;
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(obj.getClass());
            enhancer.setCallback(new MethodInterceptor() {
                @Override
                public Object intercept(Object obj, Method method, Object[] args,
                MethodProxy proxy) throws Throwable
                {
                    System.out.println("Enginner 2 writes document");
                    Object res = method.invoke(target, args);
                    return res;
                }
            }
            );
            return enhancer.create();
        }
    }

    测试代码:

    ProductOwner ross = new ProductOwner("Ross");
    
    ProductOwner rossProxy = (ProductOwner) new EnginnerCGLibProxy().bind(ross);
    
    rossProxy.defineBackLog();

    尽管ProductOwner未实现任何代码,但它也成功被代理了:

    用CGLIB实现Java动态代理的局限性

    如果我们了解了CGLIB创建代理类的原理,那么其局限性也就一目了然。我们现在做个实验,将ProductOwner类加上final修饰符,使其不可被继承:

    再次执行测试代码,这次就报错了: Cannot subclass final class XXXX。

    所以通过CGLIB成功创建的动态代理,实际是被代理类的一个子类。那么如果被代理类被标记成final,也就无法通过CGLIB去创建动态代理。

    Java动态代理实现方式三:通过编译期提供的API动态创建代理类

    假设我们确实需要给一个既是final,又未实现任何接口的ProductOwner类创建动态代码。除了InvocationHandler和CGLIB外,我们还有最后一招:

    我直接把一个代理类的源代码用字符串拼出来,然后基于这个字符串调用JDK的Compiler(编译期)API,动态的创建一个新的.java文件,然后动态编译这个.java文件,这样也能得到一个新的代理类。

    测试成功:

    我拼好了代码类的源代码,动态创建了代理类的.java文件,能够在Eclipse里打开这个用代码创建的.java文件,

    下图是如何动态创建ProductPwnerSCProxy.java文件:

    下图是如何用JavaCompiler API动态编译前一步动态创建出的.java文件,生成.class文件:

    下图是如何用类加载器加载编译好的.class文件到内存:

    如果您想试试这篇文章介绍的这四种代理模式(Proxy Design Pattern), 请参考我的github仓库,全部代码都在上面。感谢阅读。

    https://github.com/i042416/JavaTwoPlusTwoEquals5/tree/master/src/proxy

    要获取更多Jerry的原创技术文章,请关注公众号”汪子熙”或者扫描下面二维码:

    展开全文
  • 2.结构型模式,共七:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 3.行为型模式,共十一:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录...


    Java中一般认为有23种设计模式。总体来说可以分为三大类:

    • 1.创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
    • 2.结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
    • 3.行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

    单例模式

    一般分为懒汉式,饿汉式等等几种

    public class Singleton {
        /***********饿汉式**********/
        /*//直接创建对象
        public static Singleton instance = new Singleton();
        //私有化构造函数
        private Singleton(){}
        //返回对象实例
        public static Singleton getInstance(){
            return instance;
        }*/
        /************懒汉式*********/
        /*//声明对象
        private static Singleton instance = null;
        //私有化构造函数
        private Singleton(){}
        //提供对外方法
        public static Singleton getInstance(){
            if (instance == null){
                instance = new Singleton();
            }
            return instance;
        }*/
       /*************双检锁************/
    
       private static volatile Singleton instance = null;
       private Singleton(){}
       private static Singleton getInstance(){
           if (instance == null){
               synchronized (Singleton.class){
                   if (instance == null){
                       instance = new Singleton();
                   }
               }
           }
           return instance;
       }
    }
    

    工厂设计模式

    工厂模式分为工厂方法模式和抽象工厂模式。

    工厂方法模式:

    工厂方法模式分为三种:

    • 普通工厂模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。
    • 多个工厂方法模式,是对普通工厂方法模式的改进,在普通工厂方法模式中,如果传递的字符串出错,则不能正确创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象。
    • 静态工厂方法模式,将上面的多个工厂方法模式里的方法置为静态的,不需要创建实例,直接调用即可。

    下面是普通工厂模式:

    public interface Sender {
        public void send();
    }
    
    public class MailSender implements Sender{
        @Override
        public void send() {
            System.out.println("this is mail sender !");
        }
    }
    public class SmsSender implements Sender{
        @Override
        public void send() {
    
        }
    }
    public class SendFactory {
        public Sender produce(String type){
            if ("mail".equals(type)){
                return new MailSender();
            }else {
                return null;
            }
        }
    }
    
    

    多个工厂方法模式:

    public class SendFactory {
        /*******多个工厂方法模式*******/
        public Sender produceMail(){
            return new MailSender();
        }
    }
    public class FactoryTest {
        public static void main(String[] args) {
            SendFactory factory = new SendFactory();
            Sender sender = factory.produceMail();
        }
    }
    

    静态工厂方法模式:

    public class SendFactory {
        /*****静态工厂方法模式******/
        public static Sender produceMail(){
        }
        public static Sender produceSms(){
            return new SmsSender();
        }
    }
    public class FactoryTest {
        public static void main(String[] args) {
            Sender sender = SendFactory.produceMail();
            sender.send();
        }
    }
    
    抽象工厂模式

    工厂方法模式有一个问题就是,类的创建依赖工厂类,也就是说,如果想要拓展程序,必须对工厂类进行修改,这违背了闭包原则,所以,从设计角度考虑,有一定的问题,如何解决?就用到抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,直接增加新的工厂类就可以了,不需要修改之前的代码。

    建造者模式(Builder)

    工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的。

    适配器模式

    适配器模式将某个类的接口转换成客户端期望的另个接口表示,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类的适配器模式、对象的适配器模式、接口的适配器模式。

    • 类的适配器模式
    public class Source {
        public void method1(){
            System.out.println("this is original method !");
        }
    }
    
    public interface Targetable {
        //与原类中的方法相同
        public void method1();
        //新类的方法
        public void method2();
    }
    public class Adapter extends Source implements Targetable{
        @Override
        public void method2() {
            System.out.println("this is targetable method!");
        }
    }
    public class AdapterTest {
        public static void main(String[] args) {
            Targetable target = new Adapter();
            target.method1();
        }
    }
    
    • 对象的适配器模式
      基本思路和类的适配器模式相同,只是将Adapter类做修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。
    public class Wrapper implements Targetable{
        private Source source;
        public Wrapper(Source source){
            super();
        }
        @Override
        public void method1() {
            source.method1();
        }
        @Override
        public void method2() {
    
        }
    }
    
    
    public class AdapterTest {
        public static void main(String[] args) {
            Source source = new Source();
            Targetable target = new Wrapper(source);
            target.method1();
            target.method2();
        }
    }
    
    
    • 接口的适配器模式
      接口的适配器模式是这样的:有时我们写的一个接口中有多个抽象方法,当我们写该接口的实现类时,必须实现该接口的所有方法,这明显有时比较浪费,因为并不是所有的方法都是我们需要的,有时只需要某一些,此处为了解决这个问题,我们引入了接口的适配器模式,借助于一个抽象类,该抽象类实现了该接口,实现了所有的方法,而我们不和原始的接口打交道,只和该抽象类取得联系,所以我们写一个类,继承该抽象类,重写我们需要的方法就行。

    观察者模式(Observer)

    观察者模式很好理解,类似于邮件订阅和RSS订阅,当我们浏览一些博客或wiki时,经常会看到RSS图标,意思就是,当你订阅了该文章,如果后续有更新,会及时的通知你。其实,简单来讲就一句话:当一个对象变化时,其他依赖该对象的对象都会收到通知,并且随着变化!对象之间是一种一对多的关系。

    public interface Observer {
        public void update();
    }
    public class Observer1 implements Observer{
        @Override
        public void update() {
            System.out.println("Observer1 has received");
        }
    }
    public class Observer2 implements Observer{
        @Override
        public void update() {
    
        }
    }
    public interface Subject {
        //增加观察者
        public void add(Observer observer);
        public void del(Observer observer);
        //通知所有的观察者
        public void notifyObserver();
        //自身的操作
        public void operation();
    }
    
    public abstract class AbstractSubject implements Subject{
        private Vector<Observer> vector = new Vector<Observer>();
        @Override
        public void add(Observer observer) {
    
        }
    
        @Override
        public void del(Observer observer) {
            vector.remove(observer);
        }
    
        @Override
        public void notifyObserver() {
            Enumeration<Observer> enumo = vector.elements();
            while (enumo.hasMoreElements()){
                enumo.nextElement().update();
            }
        }
    }
    public class MySubject extends AbstractSubject{
        @Override
        public void operation() {
            notifyObserver();
        }
    }
    public class ObserverTest {
        public static void main(String[] args) {
            Subject subject = new MySubject();
            subject.add(new Observer1());
            subject.add(new Observer2());
            subject.operation();
        }
    }
    
    展开全文
  • spring的动态的代理模式有 JDK动态代理,基于接口(默认代理模式),CGLIB动态代理(若要使用需要进行配置) JDK动态代理是由java JDK提供  其缺点是只能为接口创建代理,返回的代理对象也只能转到某个接口类型...
  • Java中的三种代理模式

    2018-08-02 14:51:17
    代理模式Java中最常用的设计模式之一,其基本功能是通过生成目标对象的代理对象来调用方法,完成方法的加强。下面我们将对三种代理模式进行学习:  (1)静态代理:  静态代理比较简单,它的基本原理是将目标...
  • java代理模式-原来你是这样的代理

    千次阅读 热门讨论 2017-03-26 23:15:03
    天在看一些框架源码时看到了一个很奇妙的设计模式,有种熟悉个感觉,一时想不出是什么模式,后面经过了解才知道是动态代理,就这样带着好奇心学习了这个模式,更深入了解代理会发现不仅静态和动态,还有很多其他的...
  • Java几种设计模式

    2021-03-10 17:27:10
    结构型模式(7):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。 行为型模式(11):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态...
  • 结构型模式(7):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。 行为型模式(11):策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、...
  • 房地产商提供房源,中介与顾客接触,而房地产商不是与顾客直接接触,这样就形成了一种代理模式(原谅一下灵魂画手哈) 有几点需要注意一下: 1.顾客只关心房地产商的房子,而不关心是谁在卖 2.代理是房租中介,顾客...
  • 记录Java几种设计模式

    2020-11-22 01:10:30
    记录Java常见的几种设计模式什么是设计模式设计模式的类型设计模式的六大原则设计模式示例单例模式工厂模式原型模式建造者模式适配器模式装饰器模式外观模式代理模式观察者模式策略模式 什么是设计模式   设计...
  • 5、几种常见的设计模式 5.1、工厂模式 5.2、抽象工厂模式 5.3、单例模式 5.4、适配器模式 5.5、装饰器模式 5.6、代理模式 5.7、策略模式 5.8、观察者模式 1、什么是设计模式?设计模式有什么用...
  • 由于代理模式相对较多,这里会提出个使用比较多的代理模式作为示例。 代理模式的实例 2.1. 远程代理模式(RMI) 远程代理实际上就是,为一个位于不同的地址空间的对象提供一个本地代理对象。这个不同的地址空间...
  • 看了代理模式个例子,找了个最形象的记录如下:(转载自 点击打开链接) 1,什么是代理模式代理模式的作用是:为其他对象提供一代理以控制对这个对象的访问。   2,策略模式有什么好处?  在某些...
  • 几种常见的代理模式: 远程代理:类似于客户端、服务器这种模式,为不同地理的对象提供局域网代理对象 虚拟代理:根据需要将资源消耗很大的对象进行延迟,真正需要的时候进行创建,浏览帖子的时候会文字和图片...
  • 茴字有四写法,单例模式有8写法。 那么什么是单例模式呢? 也就是某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法。比如Hibernate的SessionFactory,它充当数据存储源的代理,并负责创建...
  • java几种设计模式区分

    2019-11-22 11:30:26
    1.代理模式和装饰模式有什么区别 不同之处在于模式的意图。 代理模式控制对象访问权限,装饰模式用于向对象添加职责 2.状态模式和策略模式之间有什么区别 虽然这两设计模式实现非常类似,但是他们解决了不同的...
  • 设计模式-java实现代理模式(静态代理)代理模式是一通过代理对象访问目标对象(被代理对象)的设计模式,它为目标对象的间接访问提供了一个解决方法,以限制直接访问目标对象。它的特点以下点: 使用代理对象...

空空如也

空空如也

1 2 3 4 5 ... 13
收藏数 252
精华内容 100
关键字:

java代理模式有几种

java 订阅