美文网首页
策略模式、装饰器模式、代理模式

策略模式、装饰器模式、代理模式

作者: Richard_80ec | 来源:发表于2017-12-26 14:22 被阅读0次

    1 策略模式:定义一系列算法的方法,所有的算法功能相同但是实现不同。

      设计原则:
      1、封装变化
      2、多用组合,少用继承
      3、针对接口编程,不针对实现编程
    

    示例类图:


    image.png

    如上类图所示:鸭子有两个可能的行为--飞行(FlyBehavior)和呱呱叫(QuackBehavior),为适应不
    同的鸭子这两种行为的不同方式,这是会发生“变化”的部分,将它们封装起来,形成接口。然后
    设计不同的策略类继承自行为接口,不同的鸭子都组合一个(FlyBehavior)和(QuackBehavior),以组合的方式形成一个具体鸭子。而在某个具体鸭子中,真正起作用的是
    FlyBehavior和QuackBehavior的策略类即子类。
    部分代码展示:

    public abstract class Duck {
    
        protected FlyBehavior flyBehavior;
    
        protected QuackBehavior quackBehavior;
    
        public abstract void display();
    
        public void swim(){
            System.out.println("I can swim");
        }
    
        public void fly(){
            flyBehavior.fly();
        }
    
        public void quack(){
            quackBehavior.quack();
        }
    
        public void setFlyBehavior(FlyBehavior flyBehavior){
            this.flyBehavior = flyBehavior;
        }
    
        public void setQuackBehavior(QuackBehavior quackBehavior){
            this.quackBehavior = quackBehavior;
        }
    }
    
    public class MallardDuck extends Duck {
    
        public MallardDuck(){
            this.flyBehavior = new FlyWithWings();
            this.quackBehavior = new Quack();
        }
    
        @Override
        public void display(){
            System.out.println("MallardDuck display");
        }
    }
    

    2 装饰器模式:将核心功能与装饰器功能分开,以便动态添加功能。

      涉及的设计原则:
      1,对拓展开放,对修改关闭
    

    示例类图:


    image.png

    如上类图所示,所有的类都是Beverage的子类,因此所有的类都可以用Beverage的引用来指
    向,因此可以利用Beverage beverage = new Mocha(Beverage beverage)来进行反复为一杯咖
    啡中添加mocha或者whip或者soy。
    部分示例代码:

    public abstract class Beverage {
    
        String description = "UnKnow Beverage";
    
        public String getDescription(){
            return description;
        }
    
        public abstract double cost();
    }
    
    public class DarkRoast extends Beverage{
    
        public DarkRoast(){
            description = "DarkRoast ";
        }
    
        @Override
        public double cost() {
            return 0.89;
        }
    }
    
    public abstract class CondimentDerator extends Beverage{
    
        public abstract String getDescription();
    }
    
    public class Mocha extends CondimentDerator{
        Beverage beverage;
    
        public Mocha(Beverage beverage){
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + " Mocha";
        }
    
        @Override
        public double cost() {
            return beverage.cost() + 0.15;
        }
    }
    
    public class Whip extends CondimentDerator{
    
        Beverage beverage;
    
        public Whip(Beverage beverage){
            this.beverage = beverage;
        }
    
        @Override
        public String getDescription() {
            return beverage.getDescription() + " Whip";
        }
    
        @Override
        public double cost() {
            return beverage.cost()+0.12;
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Beverage beverage1 = new DarkRoast();
            beverage1 = new Mocha(beverage1);
            beverage1 = new Mocha(beverage1);
            beverage1 = new Whip(beverage1);
            System.out.println("超优深焙咖啡,双份摩卡,打泡:" + beverage1.getDescription());
            System.out.println("cost:" + beverage1.cost() + "$");
    
            Beverage beverage2 = new HouseBlend();
            beverage2 = new Soy(beverage2);
            beverage2 = new Mocha(beverage2);
            beverage2 = new Whip(beverage2);
            System.out.println("首选咖啡:" + beverage2.getDescription());
            System.out.println("cost : " + beverage2.cost() + "$");
        }
    }
    

    3 代理模式

    3.1 远程代理模式:利用javaRMI作代理,使另一个JVM上运行的对象可以在本地JVM上获取到。

    图形示例:


    图形来自header first 设计模式

    客户端要获取服务端的某个对象,实际上是向RMI registry做请求,获取到服务器上的某个远程
    对象,而这个远程对象又是服务器在编译的时候注册到RMI上的。因此,在客户端和服务端之间
    就建立了一个以RMI registry做代理的通讯。
    部分代码示例:
    (1) 服务端将某个对象设置为远程对象,需要拓展(或继承)Remote接口---在java.rmi.*包中

    public interface GumballMachineRemote extends Remote {
    
        int getCount()throws RemoteException;
        String getLocation() throws RemoteException;
        String getState() throws RemoteException;
    }
    

    (2)在服务端写远程对象的具体实现,,java.rmi.server.UnicastRemoteObject 所有可以被远程调用的对象都必须扩展该类

    public class GumballMachine extends UnicastRemoteObject implements GumballMachineRemote {
    
        private String location;
        private int count;
    
        public GumballMachine(String location,int count) throws RemoteException{
            this.count = count;
            this.location = location;
        }
    
        @Override
        public int getCount() throws RemoteException {
            return count;
        }
    
        @Override
        public String getLocation() throws RemoteException {
            return location;
        }
    
        @Override
        public String getState() throws RemoteException {
            return "state";
        }
    }
    

    (3) 服务端将远程对象注册进入RMI registry中

    public class GumballMachineTestDrive {
    
        public static void main(String[] args) {
            try {
                //启动RMI注册服务,指定端口为1099 (1099为默认端口)
                LocateRegistry.createRegistry(1099);
                //创建服务对象
                GumballMachineRemote gumballMachine = new GumballMachine("10.0.0.1",5);
                //把gumballMachine注册到RMI注册服务器上,命名为gumballMachine
                Naming.rebind("gumballMachine",gumballMachine);
            }catch (RemoteException | MalformedURLException e){
                e.printStackTrace();
            }
        }
    }
    

    (4) 书写客户端程序

    public class GumballMonitor {
    
        GumballMachineRemote gumballMachineRemote;
    
        public GumballMonitor(GumballMachineRemote machineRemote){
            this.gumballMachineRemote = machineRemote;
        }
    
        public void report(){
            try{
                System.out.println("Gumball Machine:" + gumballMachineRemote.getLocation());
                System.out.println("Current inventory:" + gumballMachineRemote.getCount() + " gumballs");
                System.out.println("Current state:" + gumballMachineRemote.getState());
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    

    (5) 客户端调用测试:

    public class GumballMonitorTestDrive {
    
        public static void main(String[] args) {
            try {
                GumballMachineRemote gumballMachineRemote = (GumballMachineRemote) Naming.lookup("rmi://127.0.0.1:1099/gumballMachine");
                GumballMonitor gumballMonitor = new GumballMonitor(gumballMachineRemote);
                gumballMonitor.report();
            } catch (NotBoundException | MalformedURLException | RemoteException e) {
                e.printStackTrace();
            }
        }
    }
    

    3.2 虚拟代理模式:对于一些占用系统资源较多或者加载时间较长的对象,可以给这些对象

    提供一个虚拟代理。在真实对象创建成功之前虚拟代理扮演真实对象的替身,而当真实对象创建
    之后,虚拟代理将用户的请求转发给真实对象。
    图形示例:


    图形来自header first 设计模式

    如图所示:在客户端发出请求的时候,首先是代理进行处理,代理在开始创建对象的同时,会给
    客户端提供一个返回值,而不是让客户端进行无意义地等待中,知道真实对象创建成功后,则会
    将请求委托给真实对象。
    图片处理的时候,用虚拟代码显示良好信息的代码示例:

    public class ImageProxy implements Icon {
    
        private ImageIcon imageIcon;
        private URL imageURL;
        private Thread retrievalThread;
        private boolean retrieving = false;
    
        @Override
        public void paintIcon(final Component c, Graphics g, int x, int y) {
            if(imageIcon != null){
                imageIcon.paintIcon(c,g,x,y);
            }else {
                g.drawString("Loading image....",x+300,y+300);
                if(!retrieving){
                    retrieving = true;
                    retrievalThread = new Thread(new Runnable() {
                        @Override
                        public void run() {
                            try{
                                imageIcon = new ImageIcon(imageURL,"CD Cover");
                                c.repaint();
                            }catch (Exception e){
                                e.printStackTrace();
                            }
                        }
                    });
                    retrievalThread.start();
                }
            }
        }
    
        @Override
        public int getIconWidth() {
            if(imageIcon != null){
                return imageIcon.getIconWidth();
            }else {
                return 800;
            }
        }
    
        @Override
        public int getIconHeight() {
            if(imageIcon != null){
                return imageIcon.getIconHeight();
            }else {
                return 600;
            }
        }
    }
    

    在创建真实对象ImageIcon之前,会给客户端显示"Loading Image...”的提示信息

    3.3 静态代理:静态代理是最简单的一种代理模式,在程序运行前,某个类的代理委托关系

    已经确定好了。
    类图示例:


    图形来自header first 设计模式

    代码示例:(出处:https://www.jianshu.com/p/a8aa6851e09e)

    public interface Subject {  
         public void buyMac();
    }
    
    public class RealSubject implement Subject{
        @Override
        public void buyMac() {  
            System.out.println(”买一台Mac“);  
        }  
    }
    
    public class Proxy  implements Subject{
      
        @Override
        public void buyMac{
          
          //引用并创建真实对象实例,即”我“
          RealSubject realSubject = new RealSubject();
    
          //调用真实对象的方法,进行代理购买Mac
          realSubject.buyMac();
          //代理对象额外做的操作
          this.WrapMac();
        }
    
         public void WrapMac(){
          System.out.println(”用盒子包装好Mac“);  
        }
    }
    
    public class ProxyPattern {
    
        public static void main(String[] args){
    
        Subject proxy = new Proxy();
        proxy.buyMac();
        }
            
    }
    

    3.4 动态代理(保护代理):在程序运行时动态创建一个代理类,实现一个或多个接口,并

    将方法的调用转发到指定的类中。
    类图:


    图形来自Header first 设计模式

    创建动态代理类需要通过调用Proxy的静态方法newProxyInstance方法,即:

    static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,                                        
                                                       InvocationHandler h)
    
    ClassLoader loader:被代理类的类加载器(可以通过反射获取,如:person.getClass().getClassLoader())
    Class<?>[] interfaces:被代理类要实现的接口列表(可以通过反射获取,如:person.getClass().getInterfaces())
    InvocationHandler h:代理处理程序(即实现InvocationHandler接口的代理类)
    

    创建一个代理类示例:

    PersonBean personBean = (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader,
                                                                   person.getClass().getInterfaces(),
                                                                   new OwnerInvocationHandler(person))
    

    动态代理的类都需要继承InvocationHandler类,这个类中只有一个方法:

    Object invoke(Object proxy, Method method, Object[] args)
    
    Ojbect proxy:表示需要代理的对象
    Method method:表示要操作的方法
    Object[] args:method方法所需要传入的参数(可能没有为,null.也可能有多个)
    

    代码示例:
    建立被代理类接口和实现类

    public interface PersonBean {
    
        String getName();
        String getGender();
        String getInterests();
        int getHotOrNotRating();
    
        void setName(String name);
        void setGender(String gender);
        void setInterests(String interests);
        void setHotOrNotRating(int rating);
    }
    
    class PersonBeanImpl implements PersonBean{
    
        private String name;
        private String gender;
        private String interests;
        private int rating;
        private int ratingCount = 0;
    
        @Override
        public String getName() {
            return name;
        }
    
        @Override
        public String getGender() {
            return gender;
        }
    
        @Override
        public String getInterests() {
            return interests;
        }
    
        @Override
        public int getHotOrNotRating() {
            if(ratingCount == 0) return 0;
            return (rating/ratingCount);
        }
    
        @Override
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        @Override
        public void setInterests(String interests) {
            this.interests = interests;
        }
    

    建立动态代理类:

    class NonOwnerInvocationHandler implements InvocationHandler {
        private PersonBean personBean;
    
        NonOwnerInvocationHandler(PersonBean personBean) {
            this.personBean = personBean;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            try {
                if(method.getName().equals("setHotOrNotRating")) {
                    return  method.invoke(personBean, args);
                } else  if(method.getName().startsWith("set")){
                    throw new IllegalAccessException();
                }
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    
    class OwnerInvocationHandler implements InvocationHandler {
        private PersonBean personBean;
    
        OwnerInvocationHandler(PersonBean personBean){
            this.personBean = personBean;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            try{
                if(method.getName().startsWith("get")){
                    return method.invoke(personBean,args);
                }else if(method.getName().equals("setHotOrNotRating")){
                    throw new IllegalAccessException();
                }else if(method.getName().startsWith("set")){
                    return method.invoke(personBean,args);
                }
            }catch (InvalidParameterException e){
                e.printStackTrace();
            }
            return null;
        }
    }
    

    测试类:

    public class MatchMakingTestDrive {
        public static void main(String[] args) {
            PersonBean person = new PersonBeanImpl();
            person.setGender("male");
            person.setName("richard");
            person.setInterests("reading");
            person.setHotOrNotRating(5);
            System.out.println("has made personBean!");
    
            PersonBean ownerPerson = getOwnerProxy(person);
            try {
                ownerPerson.setHotOrNotRating(1);
            } catch (Exception e) {
                System.out.println("owner can't setHotOrNotRating");
            }
            ownerPerson.setInterests("science");
    
            PersonBean nonOwnerPerson = getNonOwnerProxy(person);
            try {
                nonOwnerPerson.setInterests("write");
            } catch (Exception e) {
                System.out.println("nonOwner can't setInterests");
            }
            nonOwnerPerson.setHotOrNotRating(10);
    
        }
    
        private static PersonBean getOwnerProxy(PersonBean person) {
            return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
                    person.getClass().getInterfaces(),
                    new OwnerInvocationHandler(person));
        }
    
        private static PersonBean getNonOwnerProxy(PersonBean person) {
            return (PersonBean)Proxy.newProxyInstance(person.getClass().getClassLoader(),
                    person.getClass().getInterfaces(),
                    new NonOwnerInvocationHandler(person));
        }
    }
    

    3.5 cglib动态代理:对于有接口的类,可以用上述动态代理,当某个实现类没有实现接口时,就需要用cglib动态代理。

    原文见:http://blog.csdn.net/yakoo5/article/details/9099133/
    代码示例:
    被代理类:

    public class SayHello {  
       public void say(){  
       System.out.println("hello everyone");  
       }  
    } 
    

    该类实现了创建子类的方法与代理的方法。getProxy(SuperClass.class)方法通过入参即父类的
    字节码,通过扩展父类的class来创建代理对象。intercept()方法拦截所有目标类方法的调用,obj
    表示目标类的实例,method为目标类方法的反射对象,args为方法的动态入参,proxy为代理类
    实例。proxy.invokeSuper(obj, args)通过代理类调用父类中的方法。

    public class CglibProxy implements MethodInterceptor{  
     private Enhancer enhancer = new Enhancer();  
     public Object getProxy(Class clazz){  
      //设置需要创建子类的类  
      enhancer.setSuperclass(clazz);  
      enhancer.setCallback(this);  
      //通过字节码技术动态创建子类实例  
      return enhancer.create();  
     }  
     //实现MethodInterceptor接口方法  
     public Object intercept(Object obj, Method method, Object[] args,  
       MethodProxy proxy) throws Throwable {  
      System.out.println("前置代理");  
      //通过代理类调用父类中的方法  
      Object result = proxy.invokeSuper(obj, args);  
      System.out.println("后置代理");  
      return result;  
     }  
    }  
    

    测试:

    public class DoCGLib {  
     public static void main(String[] args) {  
      CglibProxy proxy = new CglibProxy();  
      //通过生成子类的方式创建代理类  
      SayHello proxyImp = (SayHello)proxy.getProxy(SayHello.class);  
      proxyImp.say();  
     }  
    }
    

    结果:

    前置代理  
    hello everyone  
    后置代理 
    

    总结

    策略模式是定义某个接口,以不同的实现类来代替实现某种功能,

    这些实现类的功能是一样的,但是具体实现方式不同。

    装饰器模式是定义不同的装饰类,这些装饰类都是核心类的子类,

    同时核心类也是这些装饰类的一个属性,可以动态地为该核心类动态添加不同的功能模块(装饰类)

    代理模式是将某个具体类包装起来,通过代理类来处理消费方和生产方之间的交互,

    同时也可以在代理类中添加一些额外的操作。

    相关文章

      网友评论

          本文标题:策略模式、装饰器模式、代理模式

          本文链接:https://www.haomeiwen.com/subject/dukdgxtx.html