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 {@Overridepublic void offer_220v_energy() {System.out.println("家庭插座可以提供220v电压");}
}
//3.Usb供电接口
public interface UsbSocket {void offer_5v_energy();
}
//4.手机充电器使用usb电源接口
public class PhoneUsbChager implements UsbSocket {@Overridepublic 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 {@Overridepublic 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;}@Overridepublic 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 {@Overridepublic void fastenOnce() {System.out.println("烧1L汽油加速1次");}
}
//3.引擎接口实现类2柴油发动机
public class DieselEngine implements Engine {@Overridepublic 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);}@Overridepublic void fastToMax() {//小轿车加速最高次需要引擎加速1次System.out.println("小轿车加速到最高速,需要引擎加速1次");mEngine.fastenOnce();}
}
//6.抽象类Car的第1种实现类2 货车,
public class FreightCar extends Car {public FreightCar(Engine engine) {super(engine);}@Overridepublic 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{@Overridepublic boolean hasNext() {return false;}@Overridepublic Object next() {return null;}@Overridepublic 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);}@Overridepublic boolean hasNext() {if (stack.empty()) {return false;}//取出栈中最上层的迭代器进行迭代Iterator iterator = stack.peek();if (!iterator.hasNext()) {//如果最上层的迭代器迭代完了,取出下一层的迭代器进行迭代stack.pop();return hasNext();} else {return true;}}@Overridepublic Object next() {if (hasNext()) {//取出栈中最上层的迭代器进行转到下一项目Iterator iterator = stack.peek();MenuComponent mMenuComponent = (MenuComponent) iterator.next();stack.push(mMenuComponent.getIterator());return mMenuComponent;}return null;}@Overridepublic 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;}@Overridepublic String getName(){return name;}@Overridepublic String getDescription(){return description;}@Overridepublic float getPrice(){return price;}@Overridepublic boolean  isVegetable(){return vegetable;}@Overridepublic void print() {// TODO Auto-generated method stubSystem.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());}@Overridepublic 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());}@Overridepublic 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;}@Overridepublic boolean hasNext() {if (position < numberOfItems) {return true;}return false;}@Overridepublic Object next() {MenuComponent menuItem = menuItems[position];position++;return menuItem;}@Overridepublic void remove() {}}@Overridepublic 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 {@Overridepublic 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;};@Overridepublic float cost() {return super.getPrice() + Obj.cost();//在被装饰者的属性上修改属性,表达了装饰功能}@Overridepublic 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();}@Overridepublic 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");//调用代理接口拿到了服务端对象的数据,这样通过了代理实现了ipcString 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 互相交流,这里有技术美女调戏,有开发小哥勾搭
我是”努力的人最幸运”!

JAVA23种设计模式(2)-结构型模式7种相关推荐

  1. 备战面试日记(3.3) - (设计模式.23种设计模式之结构型模式)

    本人本科毕业,21届毕业生,一年工作经验,简历专业技能如下,现根据简历,并根据所学知识复习准备面试. 记录日期:2022.1.9 大部分知识点只做大致介绍,具体内容根据推荐博文链接进行详细复习. 文章 ...

  2. Java23种设计模式——11.结构型模式之享元模式

    Java中除去有设计原则之外,还有23中设计模式. 这些模式都是前辈们一点一点积累下来,一直在改进,一直在优化的,而这些设计模式可以解决一些特定的问题. 并且在这些模式中,可以说是将语言的使用体现的淋 ...

  3. Java经典23种设计模式之结构型模式(二)

    接上篇,本文介绍结构型模式里的组合模式.装饰模式.外观模式. 一.组合模式(Composite) 组合模式:将对象组合成树形结构,表示"部分--整体"的层次结构.最终达到单个对象和 ...

  4. 设计模式之结构型模式(5种)

    目录 结构型模式(Structural Pattern):怎么构造一个对象(行为.属性) 一.适配器模式 二.桥接模式(Bridge) 三.装饰者模式 设计模式在JAVA I/O库中的应用 案例 使用 ...

  5. 23种设计模式(第三章结构型模式7种)

    结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构.它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦 ...

  6. 设计模式05——结构型模式

    一.概述  结构型模式描述如何将类或对象按某种布局组成更大的结构.它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象.由于组合关系或聚合关系比继承关系耦合 ...

  7. 设计模式 之 结构型模式

    设计模式 之 结构型模式 模式 & 描述 包括 结构型模式 这些设计模式关注类和对象的组合.继承的概念被用来组合接口和定义组合对象获得新功能的方式. 适配器模式(Adapter Pattern ...

  8. 设计模式3——结构型模式

    结构型模式描述如何将类或对象按某种布局组成更大的结构,它分为类结构型和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦合度低,满足&q ...

  9. 设计模式:结构型模式-桥接、外观、组合、享元模式

    结构型模式 结构型模式描述如何将类或对象按某种布局组成更大的结构.它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者采用组合或聚合来组合对象. 由于组合关系或聚合关系比继承关系耦 ...

最新文章

  1. Android 防止快速点击
  2. 剑指offer十:矩形覆盖
  3. 胡润2019中国人工智能企业百强榜:北京55家居首
  4. day14 集合与函数
  5. CVPR 2020 Oral 汇总:论文 / 代码 / 解读(更新中)
  6. [iOS] dom解析xml数据,拿到lt;gt;里面的值
  7. angularjs-数据同步时机ng-model-options
  8. 关于RMAN recover 过程的讨论
  9. javascript ES3小测试
  10. HTML插入Flash的全兼容完美解决方案-SWFObject
  11. Win10系统中破解软件的注册机被自动删除的解决方法
  12. 离散分布的分布函数_数据分析|概率分布
  13. 风险评估-HEAVENS
  14. 《父与子的编程之旅——Python》(一)序章-第一章-第二章
  15. (21) 出行需求预测新视角---基于图卷积神经网络GCN的出租车OD需求预测
  16. The container name /mysql is already in use by container
  17. PHP 获取两个日期的相隔天数
  18. [数据仓库]电商核心业务知识之订单商品模块
  19. fxsvr2.exe
  20. rn如何测试数据请求时间_宝妈ispn/rn双证励志锦囊

热门文章

  1. 一篇精彩的创业励志演讲稿
  2. python爬取b站弹幕并进行数据可视化
  3. 网站空间服务器系统,网站空间操作系统
  4. Android实现公共公钥加密私钥解密(可分段加密分段解密)
  5. CAD 图形单位设置
  6. 怎么把ppt文字大小设置一致_?课件类PPT怎么做才好看?我修改了6页PPT,总结了7个技巧...
  7. Java实现 蓝桥杯 算法提高 三角形
  8. python爬取素材图片代码_一篇文章教会你利用Python网络爬虫获取素材图片
  9. 第二章 TCP/IP 基础知识
  10. c++ ——初次见面,请多指教