JAVA23种设计模式(2)-结构型模式7种

JAVA23种设计模式(2)-结构型模式7种

把类结合在一起形成更大的结构

适配器模式(adapter)

一句话:将一个类的接口转换成另一种接口.让原本接口不兼容的类可以兼容

这是平时比较常见的一种模式
正如名字一样,比如,手机充电器是链接220v的插座的,必须使用适配器将其转成5v输出,2A的usb通用接口给手机使用,手机中的电量肯定是来自于220v的插座,但是经过手机适配器的转化后就可以给手机使用了.
java中比如mySql等开源数据库的驱动只要实现jdbc接口就可以进行调用,这也是适配器思想的体现.这种模式正是为了解决不同库或软件之间接口不匹配问题出现的

JAVA中有类适配器和对象适配器,
1.类适配器就是通过实现目标接口和继承被适配者来实现适配的;
2.对象适配器也是实现目标接口,然后使用组合,将被适配者做为构造函数的参数传入进行适配;
两者都能达到适配的目的.

类适配器

//1.220v插口接口
public interface ChargeSocket {
   void offer_220v_energy();
}
//2.家庭插座实现220v的供电接口
public class HomeChargeSocket implements ChargeSocket {
    @Override
    public void offer_220v_energy() {
           System.out.println("家庭插座可以提供220v电压");
    }
}
//3.Usb供电接口
public interface UsbSocket {
    void offer_5v_energy();
}
//4.手机充电器使用usb电源接口
public class PhoneUsbChager implements UsbSocket {
    @Override
    public void offer_5v_energy() {
        System.out.println("usb可以提供5v电源");
    }
}
//5.定义一个手机对象类需要充电,注意一下,它只接收usb充电,并且电源来自家庭插座
public class MobilePhone {
    public  void chargeEnergy(UsbSocket usbSocket)
    {
        System.out.println("开始充电啦");
        usbSocket.offer_5v_energy();
    }
}
//6.如果使用类适配器目标接口就是UsbSocket,被适配者就是HomeChargeSocket,那是实现就是.
public class PhoneAdapter4ClassAdapter extends HomeChargeSocket implements UsbSocket {
    @Override
    public void offer_5v_energy() {
        super.offer_220v_energy();
        System.out.println("类适配器经过线圈转化后变成5v电压");
    }
}
//7.如果使用对象适配器,那么目标接口还是UsbSocket,被适配者作为参数传入
public class PhoneAdapter4ObjectAdapter implements UsbSocket{
    ChargeSocket mHomeSocket;
    public PhoneAdapter4ObjectAdapter(ChargeSocket homeSocket) {
        mHomeSocket=homeSocket;
    }
    @Override
    public void offer_5v_energy() {
        mHomeSocket.offer_220v_energy();
        System.out.println("对象适配器经过转化后成为了5v电压");
    }
}
//两个适配器写好,使用的话如下
public class Main {
    public static void main(String[] args) {
        MobilePhone mobilePhone = new MobilePhone();
      //类适配器使用
        mobilePhone.chargeEnergy(new PhoneAdapter4ClassAdapter());
        //对象适配器使用
        mobilePhone.chargeEnergy(new PhoneAdapter4ObjectAdapter(new HomeChargeSocket()));
    }
}

桥接模式(Bridging)

一句话:将实现与抽象放在两个不同的类层次中,使两个层次可以独立变化

实现指的是一个接口不同的实现,抽象指的是抽象类,如图
这里写图片描述
我的理解是一个抽象类有一个成员变量是接口,这样这个成员变量有不同的实现类代表的是第一个维度,
第二个维度指的就是这个抽象类在实现成实例的时候有不同的实现来体现第二个维度

//1.定义一个汽车引擎接口,作为第一个变化维度
public interface Engine {
    void fastenOnce();
}
//2.引擎接口实现类1汽油发动机
public class GasolineEngine implements Engine {
    @Override
    public void fastenOnce() {
        System.out.println("烧1L汽油加速1次");
    }
}
//3.引擎接口实现类2柴油发动机
public class DieselEngine implements Engine {
    @Override
    public void fastenOnce() {
        System.out.println("烧1升柴油加速1次");
    }
}
//4.定义一个抽象类Car作为第二个变化维度,需要桥接的地方将接口Engine(第1维度)作为参数传入
public abstract class Car {
    protected Engine mEngine;//成员变量是接口,可以有不同实现
    public Car(Engine engine) {
        mEngine=engine;
    }
    //抽象方法可以有不同实现 将其加速到最高速可以有不同的实现
    public abstract void fastToMax();
}
//5.抽象类Car的第1种实现类1 小轿车,
public class MobileCar extends Car {
    public MobileCar(Engine engine) {
        super(engine);
    }
    @Override
    public void fastToMax() {
        //小轿车加速最高次需要引擎加速1次
        System.out.println("小轿车加速到最高速,需要引擎加速1次");
        mEngine.fastenOnce();
    }
}
//6.抽象类Car的第1种实现类2 货车,
public class FreightCar extends Car {
    public FreightCar(Engine engine) {
        super(engine);
    }
    @Override
    public void fastToMax() {
        //货车较重,需要加速加速两次到底最高速
        System.out.println("货车加速到最高速需要引擎加速两次");
        mEngine.fastenOnce();
        mEngine.fastenOnce();
    }
}
//7.测试,不同车,不同发动机 两个维度不同实现测试
public class Main {
    public static void main(String[] args) {
        //汽油小车
        Car car1=new MobileCar(new GasolineEngine());
        car1.fastToMax();
        //汽油货车
        Car car2=new FreightCar(new GasolineEngine());
        car2.fastToMax();
        //柴油小车
        Car car3=new MobileCar(new DieselEngine());
        car3.fastToMax();
        //柴油货车
        Car car4=new FreightCar(new DieselEngine());
        car4.fastToMax();
    }
}

适用场合:系统有二维角度分类时,而每一维又有可能变化,考虑使用桥接模式,如同上例,汽车加速根据引擎两种,车型两种,最后有四个不同变化

组合模式(Compose)

一句话:将对象聚合成树形结构来表现“整体/部分”的层次结构。

组合模式能让客户以一致的方式处理个别对象以及对象组合
也就是我们可以忽略对象组合和个体对象之间的差别
这种模式是对树状结构子项做一致处理,并且非常容易拓展新的子项或者是新根节点而又不影响原定的处理算法
就像菜单中有的是子项目,但也有子菜单,子菜单中又有子项目,首先,子项目只有一个,因此没有存在迭代的可能,而子菜单中是有一组子项目,传统的迭代器无法满足需求,因此我们用装饰模式给这一组子项目的迭代器修改新功能

import java.util.Iterator;
//1.定义的空迭代器对应子项目中使用
public class NullIterator implements Iterator{
    @Override
    public boolean hasNext() {
        return false;
    }
    @Override
    public Object next() {
        return null;
    }
    @Override
    public void remove() {  
    }
}

import java.util.Iterator;
import java.util.Stack;
//2.对于子菜单中的多项目的迭代器需要改动,使用装饰模式进行改动
public class ComposeIterator implements Iterator {
    //使用栈结构来保证可以有多个子节点的迭代
    private Stack<Iterator> stack = new Stack<Iterator>();
    public ComposeIterator(Iterator iterator) {
        stack.push(iterator);
    }
    @Override
    public boolean hasNext() {
        if (stack.empty()) {
            return false;
        }
        //取出栈中最上层的迭代器进行迭代
        Iterator iterator = stack.peek();
        if (!iterator.hasNext()) {
            //如果最上层的迭代器迭代完了,取出下一层的迭代器进行迭代
            stack.pop();
            return hasNext();
        } else {
            return true;
        }
    }
    @Override
    public Object next() {
        if (hasNext()) {
          //取出栈中最上层的迭代器进行转到下一项目
            Iterator iterator = stack.peek();
            MenuComponent mMenuComponent = (MenuComponent) iterator.next();
            stack.push(mMenuComponent.getIterator());
            return mMenuComponent;
        }
        return null;
    }

    @Override
    public void remove() {
    }
}
import java.util.Iterator;
//3.首先,定义子项目和子菜单共同的父类
public abstract class MenuComponent {
    public String getName() {
        return "";
    }
    public String getDescription() {
        return "";
    }
    public float getPrice() {
        return 0;
    }
    public boolean isVegetable() {
        return false;
    }
    public abstract void print();

    public Iterator getIterator() {
        return new NullIterator();
    }
}
//4.定义子项目,继承自MenuComponent
public class MenuItem extends MenuComponent{
    private String name,description;
    private boolean vegetable;
    private float price;
    public MenuItem(String name,String description,boolean vegetable,float price)
    {
        this.name=name;
        this.description=description;
        this.vegetable=vegetable;
        this.price=price;

    }
    @Override
    public String getName()
    {
        return name;
    }
    @Override
    public String getDescription()
    {
        return description;
    }
    @Override
    public float getPrice()
    {
        return price;
    }
    @Override
    public boolean  isVegetable()
    {
        return vegetable;
    }
    @Override
    public void print() {
        // TODO Auto-generated method stub
        System.out.println(getName() + "***" + getPrice() + "***"
                + getDescription());

    }
}
import java.util.ArrayList;
import java.util.Iterator;
//5.定义子菜单,添加了一个ArrayList保存子项目
public class CakeHouseMenu extends MenuComponent {
    private ArrayList<MenuComponent> menuItems;
    public CakeHouseMenu() {
        menuItems = new ArrayList<MenuComponent>();
        //这个子菜单中有四个子项目
        addItem("肯德基蛋糕", "煎蛋,土豆,菜花", true, 3.99f);
        addItem("麦当劳蛋糕", "炸蛋 土司", false, 3.59f);
        addItem("草莓蛋糕", "新鲜草莓派", true, 3.29f);
        addItem("常规蛋糕早餐", "香肠 土豆", true, 2.59f);
    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }

    public Iterator getIterator() {
        //使用装饰模式,将ArrayList修改后的迭代器传出
        return new ComposeIterator(menuItems.iterator());
    }

    @Override
    public void print() {
        System.out.println("****这是蛋糕菜单****");
    };

    // 其他功能代码

}
import java.util.ArrayList;
import java.util.Iterator;
//6.定义子菜单2,添加了一个ArrayList保存子项目
public class SubMenu extends MenuComponent {
    private ArrayList<MenuComponent> menuItems;
    public SubMenu() {
        //这个子菜单中有三个子项目
        menuItems = new ArrayList<MenuComponent>();
        addItem("苹果曲奇", "苹果美味", true, 1.99f);
        addItem("香蕉曲奇", "香蕉美味", false, 1.59f);
        addItem("橘子曲奇", "橘子美味", true, 1.29f);
    }

    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        menuItems.add(menuItem);
    }

    public Iterator getIterator() {
        return new ComposeIterator(menuItems.iterator());
    }

    @Override
    public void print() {
        System.out.println("****这是曲奇菜单****");
    };
    // 其他功能代码

}
import java.util.Iterator;
//7.定义第3个子菜单 中午餐菜单,定义最大项只有5,numberOfItems作为记录数字,使用数组结构来装子项目
public class DinerMenu extends MenuComponent {
    private final static int Max_Items = 5;
    private int numberOfItems = 0;
    private MenuComponent[] menuItems;

    public DinerMenu() {
        //这个子菜单中有4个子菜单并且有1个子项目
        menuItems = new MenuComponent[Max_Items];
        addItem("蔬菜煎饼", "培根,蔬菜,土豆", true, 3.58f);
        addItem("肉饼", "西红柿,猪肉", false, 3.00f);
        addItem("豆汤", "土豆,沙拉", true, 3.28f);
        addItem("热狗", "洋葱,猪肉", false, 3.05f);
        addSubMenu(new SubMenu());

    }
    //增加子项目的方法
    private void addItem(String name, String description, boolean vegetable,
            float price) {
        MenuItem menuItem = new MenuItem(name, description, vegetable, price);
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = menuItem;
            numberOfItems++;
        }

    }
    //增加子菜单的方法
    private void addSubMenu(MenuComponent mMenuComponent) {
        if (numberOfItems >= Max_Items) {
            System.err.println("sorry,menu is full!can not add another item");
        } else {
            menuItems[numberOfItems] = mMenuComponent;
            numberOfItems++;
        }

    }
    public Iterator getIterator() {
        //将数组的迭代器进行更改
        return new ComposeIterator(new DinerIterator());
    }

    //这里为数组结构做了一个迭代器
    class DinerIterator implements Iterator {
        private int position;

        public DinerIterator() {
            position = 0;
        }

        @Override
        public boolean hasNext() {
            if (position < numberOfItems) {
                return true;
            }

            return false;
        }

        @Override
        public Object next() {
            MenuComponent menuItem = menuItems[position];
            position++;
            return menuItem;
        }

        @Override
        public void remove() {

        }
    }

    @Override
    public void print() {
        System.out.println("****这是 中午餐菜单****");
    };
}
import java.util.ArrayList;
import java.util.Iterator;
//8.最后定义出一个根节点,使用ArrayList保存节点
public class Waitress {
    private ArrayList<MenuComponent> iterators = new ArrayList<MenuComponent>();

    public Waitress() {

    }

    public void addComponent(MenuComponent mMenuComponent) {
        iterators.add(mMenuComponent);

    }

    public void printMenu() {
        //在根节点中定义方法对所有的子节点进行一致性的操作,体现了组合模式的意义,拓展性强
        Iterator iterator;
        MenuComponent menuItem;
        for (int i = 0, len = iterators.size(); i < len; i++) {
            //根节点的二级节点展示
            iterators.get(i).print();
            //根节点的三级以后节点展示
            iterator = iterators.get(i).getIterator();
            while (iterator.hasNext()) {
                menuItem = (MenuComponent) iterator.next();
                menuItem.print();
            }
        }
    }


    public void printVegetableMenu() {

        Iterator iterator;
        MenuComponent menuItem;
        for (int i = 0, len = iterators.size(); i < len; i++) {
            iterators.get(i).print();
            iterator = iterators.get(i).getIterator();

            while (iterator.hasNext()) {
                menuItem = (MenuComponent) iterator.next();
                if (menuItem.isVegetable()) {
                    menuItem.print();
                }
            }

        }

    }
}
 //9.对组合模式的节点树进行测试
public class MainTest {
    public static void main(String[] args) {
        Waitress mWaitress = new Waitress();
        CakeHouseMenu mCakeHouseMenu = new CakeHouseMenu();
        DinerMenu mDinerMenu = new DinerMenu();
        mWaitress.addComponent(mCakeHouseMenu);
        mWaitress.addComponent(mDinerMenu);
        mWaitress.printVegetableMenu();
        mWaitress.printMenu();
    }
}

装饰模式(Decorater)

一句话:动态的将新功能附加到对象上.在对象功能拓展方面,它比继承更有弹性

首先要用java的io体系作为例子,
图1:
这里写图片描述
图2:
这里写图片描述

java的IO中的BufferedReader,BufferedWriter以及BufferedInputStream,BufferedOutputStream就是典型的装饰模式,Buffered缓存的操作就是属于新功能,同时也是io流的分支,但是又不是像FileReader,InputStreamReader这样的IO流中的详细分支,试想一下,如果每个分支因为增加新功能就添加一个子类,那么io流的体系就过于庞大,因此会有
BufferedReader buf = new BufferedReader(new FileReader(“file.java”));这样的io流功能分支同时,构造函数中又将io流做完一个参数加入进去作为被添加功能者.所以详细子类分支就是被装饰者,而Buffered这样的新功能分支就是装饰者
接下来得代码就是分为被装饰者和装饰者进行设计的
如图3.
这里写图片描述
被装饰者就是Drink的各个分支,而Decorator就是装饰者,它的父类也是Drink

//1.定义抽象类作为所有对象的父类,
//这里的两个属性description和cost,一个字符串一个浮点,这样(详细和功能)子类可以用反复修改这两个属性
//达到装饰的这种效果
public abstract class Drink {
    public String description="";
    private float price=0f;
    public void setDescription(String description)
    {
        this.description=description;
    }
    //表现字符串属性
    public String getDescription()
    {
        return description+"-"+this.getPrice();
    }
    public float getPrice()
    {
        return price;
    }
    public void setPrice(float price)
    {
        this.price=price;
    }
    //每一个子类需要定义
    public abstract float cost();
}
//2.定义被修饰的详细分支
public  class Coffee extends Drink {
    @Override
    public float cost() {
        return super.getPrice();
    }
}
//3.(被装饰)详细分支实现类1-的卡咖啡
public class Decaf extends Coffee {
    public Decaf()
    {
        super.setDescription("Decaf");
        super.setPrice(3.0f);
    }
}
4.(被装饰)详细分支实现类2-意大利浓咖啡
public class Espresso extends Coffee{
    public Espresso()
    {
        super.setDescription("Espresso");
        super.setPrice(4.0f);
    }
}

5.(被装饰)详细分支实现类3-长浓咖啡
public class LongBlack extends Coffee{
    public LongBlack()
    {
        super.setDescription("LongBlack");
        super.setPrice(6.0f);
    }
}
6.(被装饰)详细分支实现类4-短咖啡
public class ShortBlack extends Coffee{
    public ShortBlack()
    {
        super.setDescription("ShortBlack");
        super.setPrice(5.0f);
    }
}
//7.装饰者分支(功能分支,与详细分支相分离)
public class Decorator extends Drink {
    private Drink Obj;//装饰者既用上了继承同时又用上了组合,将被装饰者(详细分支作为成员变量带入类)
    public Decorator(Drink Obj) {
        this.Obj = Obj;
    };
    @Override
    public float cost() {
        return super.getPrice() + Obj.cost();//在被装饰者的属性上修改属性,表达了装饰功能
    }
    @Override
    public String getDescription() {
        return super.description + "-" + super.getPrice() + "&&" + Obj.getDescription();//在被装饰者的属性上修改属性,表达了装饰功能
    }
}
8.(装饰者)详细分支实现类1-巧克力
public class Chocolate extends Decorator {
    public Chocolate(Drink Obj) {       
        super(Obj);
        super.setDescription("Chocolate");
        super.setPrice(3.0f);
    }
}
9.(装饰者)详细分支实现类2-牛奶
public class Milk extends Decorator {
    public Milk(Drink Obj) {        
        super(Obj);
        super.setDescription("Milk");
        super.setPrice(2.0f);
    }
}
10.(装饰者)详细分支实现类3-豆奶
public class Soy extends Decorator {
    public Soy(Drink Obj) {     
        super(Obj);
        super.setDescription("Soy");
        super.setPrice(1.5f);
    }
}
//11.装饰者测试,装饰者使用修改了详细分支的属性同时避免了体系过于庞大,表现了良好的拓展性
public class CoffeeBar {
    public static void main(String[] args) {
    //这是详细分支未装饰
        Drink order;
        order=new Decaf();
        System.out.println("order1 price:"+order.cost());
        System.out.println("order1 desc:"+order.getDescription());

        System.out.println("****************");
        //详细分支被功能分支装饰1次
        order=new Milk(order);
                System.out.println("order2 price:"+order.cost());
        System.out.println("order2 desc:"+order.getDescription());
        System.out.println("****************");
        //详细分支被功能分支装饰多次
        order=new Chocolate(order);
        order=new Chocolate(order);
        System.out.println("order3 price:"+order.cost());
        System.out.println("order3 desc:"+order.getDescription());
    }
}

外观模式(Facade)

一句话:提供一个统一的接口,来访问子系统中一群功能相关接口
外观模式定义了一个高层接口,让子系统更容易使用

这个模式还是比较好理解,就像我们开车一扭车钥匙,那么控制仪启动,引擎会启动,导航仪启动,再一扭车钥匙,其他系统都跟着关闭.

//1.定义子系统1.控制仪
public class ControlPanel {
    public void startUp() {
        System.out.println("控制仪打开了");
    }
    public void shutDown() {
        System.out.println("控制仪关闭了");
    }
}
//2.定义子系统2.引擎
public class Engine {
    public void startUp() {
        System.out.println("引擎打开了");
    }
    public void shutDown() {
        System.out.println("引擎关闭了");
    }
}
//3.定义子系统3.导航仪
public class Navigator {
    public void startUp() {
        System.out.println("导航仪打开了");
    }
    public void shutDown() {
        System.out.println("导航仪关闭了");
    }
}
//4.定义一个高层接口,让子系统  更容易使用
public class Car {
    private ControlPanel panel;
    private Engine engine;
    private Navigator navigator;

    public Car() {
        navigator = new Navigator();
        engine = new Engine();
        panel = new ControlPanel();
    }

    public void startUp() {
        panel.startUp();
        engine.startUp();
        navigator.startUp();
    }
    public void shutDown() {
        navigator.shutDown();
        engine.shutDown();
        panel.shutDown();
    }
}
//5.测试,外观
public class Main {
    public static void main(String[] args) {
        Car car = new Car();
        //使用高层接口操作子系统
        car.startUp();
        System.out.println("汽车开了很久以后");
        car.shutDown();
    }
}

这个模式主要是为了让子系统与子系统减少交互,同时,这体现了迪米特原则(最少知道原则),要用高层接口去控制子系统的的使用,让使用者不需要知道子系统相关信息

蝇量模式(FlyWeight)

一句话:通过共享方式高效地支持大量细粒度的对象
蝇量模式(也叫作享元模式)的主要目的是实现对象的共享,即共享池,当系统中对象多的时候可以减少内存的开销,java中有大量的共享池保存相同的数据对象以便减少内存开销,像常量池,线程池…

我这个例子假设一个1000*1000的操场内,每个格子分配一个人,对照有模式和非模式两种代码占用内存分析

//1.定义每个角色的属性是位置(x,y)和name
public class Roler1 {
    int x;
    int y;
    String name;
    public Roler1(int x, int y, String name) {
        super();
        this.x = x;
        this.y = y;
        this.name = name;
    }

    private void display() {
        System.out.println( "Roler [x=" + x + ", y=" + y + ", name=" + name + "]");
    }
}
//2.使用池的方式建立一个Rollermanager类,这里有x坐标,y坐标,和name的池
public class RolerManager {

    int[] xArray=new int[1000];
    int[] yArray=new int[1000];
    String[] mNames=new String[1000*1000];
    public RolerManager()
    {

        for (int i = 0; i < 1000; i++) {
            for (int j = 0; j < 1000; j++) {
                xArray[i]=i;
                yArray[j]=j; 
                mNames[i*1000+j]="李四"+(i*1000+j);

            }
        }

    }
    public void displayNameByXandY(int x,int y)
    {
        System.out.println("获得的名字是" +mNames[x*1000+y]);
    }
}
//3.分别对内存消耗进行测试
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.Locale;
public class Main {
    public static void main(String[] args) {
        demo1();

        demo2();
    }

    public static void demo1()
    {
        ArrayList list= new ArrayList<Roler1>();

        for (int i = 0; i < 1000; i++) {
            for (int j = 0; j < 1000; j++) {
                list.add(new Roler1(i, j, "李四"+(i*1000+j)));
            }
        }
        showMemInfo();

    }

    public static void demo2()
    {
        RolerManager rolerManager = new RolerManager();
        rolerManager.displayNameByXandY(200, 10);
        showMemInfo();
    }

    public static void showMemInfo() {
        // 已分配内存中的剩余空间 :
        long free = Runtime.getRuntime().freeMemory();
        // 分配内存:
        long total = Runtime.getRuntime().totalMemory();
        // 最大内存:
        long max = Runtime.getRuntime().maxMemory();
        // 已占用的内存:

        long used = total - free;

        System.out.println("最大内存 = " + max/1024/1024);
        System.out.println("已分配内存 = " + total/1024/1024);
        System.out.println("已分配内存中的剩余空间 = " + free/1024/1024);
        System.out.println("已用内存 = " + used/1024/1024);
        System.out.println("时间 = " + new SimpleDateFormat("HH:ss", Locale.getDefault()).format(new Date(System.currentTimeMillis()))); ;
        System.out.println("---------------------");
    }
}

结果显示为:

 最大内存 = 1810
 已分配内存 = 154
 已分配内存中的剩余空间 = 68
 已用内存 = 85
  时间 = 16:23
  ---------------------
  获得的名字是李四200010
  最大内存 = 1810
  已分配内存 = 183
  已分配内存中的剩余空间 = 124
  已用内存 = 58
  时间 = 16:23

85-58=27m,
可以看出后面使用模式的内存比没使用节省了27m内存,使用蝇量可以到达节省内存消耗的效果

代理模式(Proxy)

一句话:为一个对象提供一个替身,以控制这个对象访问被代理的对象,可以是远程对象,创建开销大的对象或需要安全控制的对象,代理模式有很多变体,都是为了控制与管理对象访问,避免自己直接操作目标对象

例如,android中的service提供一个OnBind()方法中,返回一个Binder就是一个服务的代理对象,Activity就使用ServiceConnection去接收这个Binder,然后用Binder去操作service.
Binder是Android中的一种重要跨进程通信方式,Android中有大量的CS(Client-Server)应用方式,由于各个进程中的内存是不能共享的,因此在进程间交互(ipc)的通道就采用了代理模式,用户使用Binder这个代理对象对服务进行操作.
这里写图片描述

这里用java的RMI(Remote Method Invocation)做例子,java中的服务端代理对象必须实现自remote接口,并且同时继承UnicastRemoteObject 这个对象

//1.定义一个代理接口继承自java.rmi的remote接口
import java.rmi.Remote;
import java.rmi.RemoteException;
public interface MyRemote extends Remote{
    public String sayHello() throws RemoteException;
}
//2.创建一个服务端对象,这个对象实现了定义好的代理接口
import java.rmi.Naming;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.server.UnicastRemoteObject;
@SuppressWarnings("serial")
public class MyRemoteImpl extends UnicastRemoteObject implements MyRemote{
    protected MyRemoteImpl() throws RemoteException {
        super();
    }
    @Override
    public String sayHello() throws RemoteException {
        return "Hello World!";
    }

    public static void main(String[] args) {
        //!!这里要开启一个服务端进程,
        try {
        //创建一个代理对象,
            MyRemote service=new MyRemoteImpl();
            //这个程序注册到本机的6600端口
            LocateRegistry.createRegistry(6600);  
            //把这个服务端的代理对象绑定到本机的6600端口
            Naming.rebind("rmi://localhost:6600/RemoteHello", service);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println( e.toString());
        } 
    }
}
//3.创建一个客户端对象,在这里启动 一个客户端进程,这个进程中得到了服务端的接口,使用这个代理对象远程操作服务端对象
import java.rmi.Naming;
public class MyRemoteClient {
    public void go()
    {
        try {
        //拿到服务端代理对象
            MyRemote service=(MyRemote)Naming.lookup("rmi://localhost:6600/RemoteHello");
            //调用代理接口拿到了服务端对象的数据,这样通过了代理实现了ipc
            String s=service.sayHello();
            System.out.println(s);

        } catch (Exception e) {
            e.printStackTrace();
        } 
    }
    public static void main(String[] args) {
    //!!开启了客户端进程
        new MyRemoteClient().go();
    }
}

代理模式变形分类:
虚拟代理:虚拟代理为创建开销大的对象提供服务,例如android在线图片加载类
动态代理:运行时动态地创建代理类对象,并将方法调用转发到指定类
防火墙代理:
缓存代理:
智能引用代理:

下面讲一下java中的动态代理

Java动态代理主要涉及到两个类:
InvocationHandler:该接口中仅定义了一个Object : invoke(Object proxy, Method method, Object[] args);参数proxy指代理类,method表示被代理的方法,args为method中的参数数组,返回值Object为代理实例的方法调用返回的值。这个抽象方法在代理类中动态实现。

Proxy:所有动态代理类的父类,提供用于创建动态代理类和实例的静态方法。

所谓动态代理类是在运行时生成的class,在生成它时,你必须提供一组interface给它,则动态代理类就宣称它实现了这些interface。当然,动态代理类就充当一个代理,你不要企图它会帮你干实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。

//1 定义真实对象和代理对象的共同接口  
public interface Subject {  
    public void doSomething();  
}
//2.真实对象:定义目标操作
public class RealSubject implements Subject {  
    @Override  
    public void doSomething() {  
        System.out.println("RealSubject.doSomething");  
    }  
} 
//3.代理对象
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Method;  
public class DynamicProxy implements InvocationHandler {  
  private Object object;  
  public DynamicProxy(Object object) {  
      this.object = object;  
  }  
  @Override  
  public Object invoke(Object proxy, Method method, Object[] args)  
          throws Throwable {  
      System.out.println("Before Invoke ! method : " + method); 
      //我们可以再代理方法调用前后添加功能  
      Object result = method.invoke(object, args);          
      System.out.println("object : " + object + "\tresult : " + result + "\targs : " + args);  
      System.out.println("After Invoke !");  
      return result;  
  }  
}  
//4.客户端测试
import java.lang.reflect.InvocationHandler;  
import java.lang.reflect.Proxy;  

    public class Client {  
        public static void main(String[] args) throws Exception {  

            //创建目标对象,也就是被代理对象  
            RealSubject realSubject = new RealSubject();  

            //将目标对象交给代理  
            InvocationHandler handler = new DynamicProxy(realSubject);  

    //      Class<?> proxyClass = Proxy.getProxyClass(Subject.class.getClassLoader()  
    //              , new Class[]{Subject.class});  
    //      Subject subject = (Subject)proxyClass.getConstructor(new Class[]{InvocationHandler.class})  
    //              .newInstance(new Object[]{handler});  

            //返回代理对象,相当于上面两句  
            Subject subject = (Subject) Proxy.newProxyInstance(handler.getClass().getClassLoader(),  
                    realSubject.getClass().getInterfaces(),  
                    handler);  

            //叫代理对象去doSomething(),其实在代理对象中的doSomething()中还是会  
            //用handler来调用invoke(proxy, method, args) 参数proxy为调用者subject(this),  
            //method为doSomething(),参数为方法要传入的参数,这里没有  
            subject.doSomething();  
        }  
    }  

欢迎加入技术博客达人群-235496381 互相交流,这里有技术美女调戏,有开发小哥勾搭
我是”努力的人最幸运”!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值