一:单例模式

1.作用: 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。

2.常用应用场景:

  • Windows的Task Manager(任务管理器)就是很典型的单例模式
  • windows的Recycle Bin(回收站)也是典型的单例应用。在整个系统运行过程中,回收站一直维护着仅有的一个实例。
  • 项目中,读取配置文件的类,一般也只有一个对象。没有必要每次使用配置文件数据,每次new一个对象去读取。
  • 网站的计数器,一般也是采用单例模式实现,否则难以同步。
  • 应用程序的日志应用,一般都何用单例模式实现,这一般是由于共享的日志文件一直处于打开状态,因为只能有一个实例去操作,否则内容不好追加。
  • 数据库连接池的设计一般也是采用单例模式,因为数据库连接是一种数据库资源。
  • 操作系统的文件系统,也是大的单例模式实现的具体例子,一个操作系统只能有一个文件系统。
  • Application 也是单例的典型应用(Servlet编程中会涉及到)
  • 在Spring中,每个Bean默认就是单例的,这样做的优点是Spring容器可以管理
  • 在servlet编程中,每个Servlet也是单例
  • 在spring MVC框架/struts1框架中,控制器对象也是单例

3.单例模式的优点:由于单例模式只生成一个实例,减少了系统性能开销,当一个对象的产生需要 比较多的资源时,如读取配置、产生其他依赖对象时,则可以通过在应用启动 时直接产生一个单例对象,然后永久驻留内存的方式来解决。单例模式可以在系统设置全局的访问点,优化环共享资源访问,例如可以设计 一个单例类,负责所有数据表的映射处理

4.饿汉式(线程安全,调用效率高。 但是,不能延时加载。)

/**
* 类描述:   单例模式(饿汉模式)
 */
public class Singleton {
	//饿汉模式第一种:
	public static final Singleton SINGLETON=new Singleton();
	private Singleton() {};
}
/**   
* 类描述:   枚举类型表示当前对象时有限的几个,可以使用单例模式
*/
public enum Singleton2 {
	INSTANCE;
	public void singletonOperation() {
		
	}
}

枚举本身就是单例模式 ,反射无法破解

/**
* 类描述:   单例模式(饿汉模式)
 */
public class Singleton3 {
	//饿汉模式第三种:
	public static Singleton3 singleton;
	private Singleton3(String str) {
		this.str=str;
	};
	
	private String str;
	
	//通过静态代码块初始化单例,可以对成员变量进行初始化,读取外部文件
	static{
		try {
			Properties properties = new Properties();
			InputStream resourceAsStream = Singleton3.class.getClassLoader().getResourceAsStream("info.properties");
			properties.load(resourceAsStream);
			String str = properties.getProperty("str");
			singleton=new Singleton3(str);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	public String getStr() {
		return str;
	}

	public void setStr(String str) {
		this.str = str;
	}
	
}

4.懒汉式(调用效率不高。 但是,可以延时加载。)

/**
* 类描述:   单例模式(懒汉模式)
 */
public class Singleton4 {
	//懒汉模式第一种:线程不安全
	private static Singleton4 singleton;
	private Singleton4() {};
	
	public static Singleton4 getInstance() {
		if(singleton==null) {
			singleton=new Singleton4();
		}
		return singleton;
	}
	
}
/**
* 类描述:   单例模式(懒汉模式)
 */
public class Singleton5 {
	//懒汉模式第二种:双重检索机制
	private static volatile Singleton5 singleton;
	private Singleton5() {};
	public static Singleton5 getInstance() {
		if(singleton==null) {
			synchronized (Singleton5.class) {//通过同步代码块实现线程安全
				if(singleton==null) {
					singleton=new Singleton5();
				}
			}
		}
		return singleton;
	}
}
/**
* 类描述:   单例模式(懒汉模式)
 */
public class Singleton6 {
	//懒汉模式第三种:静态内部类,延迟加载,线程安全
	private Singleton6() {};
	
	public static Singleton6 getInstance() {
		return Inner.SINGLETON;
	}
	//通过内部类获取,静态内部类不会自动随着外部类初始化而初始化,用到这个类似才会初始化
	//因为是在类加载时才初始化,所以也是线程安全的
	private static class Inner{
		private static final Singleton6 SINGLETON=new Singleton6();
	}
}

5.反射破解单例模式(枚举类型除外)

public class Clien {
	public static void main(String[] args) throws Exception {
		Class<Singleton> clazz = (Class<Singleton>) Class.forName("com.peng.test.Singleton");
		Constructor<Singleton> constructor=clazz.getDeclaredConstructor(null);
		constructor.setAccessible(true);//设置可以访问是由构造方法
		Singleton instance1 = constructor.newInstance();
		Singleton instance2 = constructor.newInstance();
		System.out.println(instance1);
		System.out.println(instance2);
		
		//解决方法,在构造器中判断实例不等于null时抛出异常
//		private Singleton() {
//			if (SINGLETON!=null) {
//				throw new RuntimeException();
//			}
//		};
	}
}

6.反序列化破解单例模式(枚举除外)

public class Clien2 {
	@SuppressWarnings("resource")
	public static void main(String[] args) throws Exception {
		
		//Singleton必须实现Serializable接口
		Singleton singleton = Singleton.SINGLETON;
		FileOutputStream fileOutputStream = new FileOutputStream("d:/a.txt");
		ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
		//序列化
		objectOutputStream.writeObject(singleton);
		objectOutputStream.close();
		fileOutputStream.close();
		//反序列化
		ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("d:/a.txt"));
		Singleton readObject = (Singleton) objectInputStream.readObject();
		objectInputStream.close();
		System.out.println(singleton);
		System.out.println(readObject);
		
		/**
		 * 解决方法,在类中添加以下方法
		 * 在反序列化时直接调用这个方法将对象返回不需要在反序列化新对象
		 * private Object readResolve() throws ObjectStreamException {
			return SINGLETON;
			}
		 */
	}
}

二:工厂模式

1.工厂模式: 实现了创建者和调用者的分离,详细分类:简单工厂模式,工厂方法模式,抽象工厂模式

2.面向对象设计的基本原则:

  • OCP(开闭原则,Open-Closed Principle):一个软件的实体应当对扩展开 放,对修改关闭。
  • DIP(依赖倒转原则,Dependence Inversion Principle):要针对接口编程, 不要针对实现编程。
  • LoD(迪米特法则,Law of Demeter):只与你直接的朋友通信,而避免和 陌生人通信。

3.核心本质:实例化对象,用工厂方法代替new操作。将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实 现类解耦。

4.简单工厂模式:用来生产同一等级结构中的任意产品。(对于增加新的产品,需要修改已有代码)

  • 简单工厂模式也叫静态工厂模式,就是工厂类一般是使用静态方法, 通过接收的参数的不同来返回不同的对象实例。
  • 对于增加新产品无能为力!不修改代码的话,是无法扩展的
public interface Car {
	public void run();
}

public class Audi implements Car {
	@Override
	public void run() {
		System.out.println("奥迪..........");
	}
}

public class Byd implements Car {
	@Override
	public void run() {
		System.out.println("比亚迪......");
	}
}

/**
 * 实现调用者与创建者分离
 */
public class SimpleFactory {
	public Car createCar(String type) {
		if ("audi".equals(type)) {
			return new Audi();
		}else if("byd".equals(type)) {
			return new Byd();
		}
		return null;
	}
}

5.工厂方法模式

  • 为了避免简单工厂模式的缺点,不完全满足OCP。
  • 工厂方法模式和简单工厂模式最大的不同在于,简单工厂模式只有一个(对于一个项目 或者一个独立模块而言)工厂类,而工厂方法模式有一组实现了相同接口的工厂类。
public interface CarFactory {
	 public Car createCar();
}

public class AudiFactory implements CarFactory{
	@Override
	public Car createCar() {
		return new Audi();
	}
}

public class BydFactory implements CarFactory{
	@Override
	public Car createCar() {
		return new Byd();
	}
}

当增加奔驰类时,只需要增加一个奔驰工厂即可,不用对原有工厂进行修改。

6.简单工厂模式对比工厂方法模式

  • 结构复杂度:从这个角度比较,显然简单工厂模式要占优。简单工厂模式只需一个工厂类,而工厂方法模式的工厂类随着产品类个 数增加而增加,这无疑会使类的个数越来越多,从而增加了结构的复杂程度。
  • 代码复杂度:代码复杂度和结构复杂度是一对矛盾,既然简单工厂模式在结构方面相对简洁,那么它在代码方面肯定是比工厂方法 模式复杂的了。简单工厂模式的工厂类随着产品类的增加需要增加很多方法(或代码),而工厂方法模式每个具体工 厂类只完成单一任务,代码简洁。
  • 客户端编程难度:工厂方法模式虽然在工厂类结构中引入了接口从而满足了OCP,但是在客户端编码中需要对工厂类进行实例化。而简 单工厂模式的工厂类是个静态类,在客户端无需实例化,这无疑是个吸引人的优点。
  • 管理上的难度:这是个关键的问题。 我们先谈扩展。众所周知,工厂方法模式完全满足OCP,即它有非常良好的扩展性。那是否就说明了简单工厂模式就 没有扩展性呢?答案是否定的。简单工厂模式同样具备良好的扩展性——扩展的时候仅需要修改少量的代码(修改工 厂类的代码)就可以满足扩展性的要求了。尽管这没有完全满足OCP,但我们不需要太拘泥于设计理论,要知道, sun提供的java官方工具包中也有想到多没有满足OCP的例子啊。 然后我们从维护性的角度分析下。假如某个具体产品类需要进行一定的修改,很可能需要修改对应的工厂类。当同时 需要修改多个产品类的时候,对工厂类的修改会变得相当麻烦(对号入座已经是个问题了)。反而简单工厂没有这些 麻烦,当多个产品类需要修改是,简单工厂模式仍然仅仅需要修改唯一的工厂类(无论怎样都能改到满足要求吧?大 不了把这个类重写)。

根据设计理论建议:工厂方法模式。但实际上,我们一般都用简单工厂模式。

7.抽象工厂模式

  • 用来生产不同产品族的全部产品。(对于增加新的产品,无能为力; 支持增加产品族)
  • 抽象工厂模式是工厂方法模式的升级版本,在有多个业务品种、业务 分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。
/**
 * 发动机接口
 */
public interface Engine {
	void run();
	void start();
}

/**
 * 高端发动机实现
 */
class LuxuryEngine implements Engine{
	@Override
	public void run() {
		System.out.println("好发动机转的快......");
	}
	@Override
	public void start() {
		System.out.println("好发动机启动快......");
	}
}
/**
 * 低端发动机实现
 */
class LowEngine implements Engine{
	@Override
	public void run() {
		System.out.println("低端发动机转的慢......");
	}
	@Override
	public void start() {
		System.out.println("低端发动机启动慢......");
	}
}
/**
 * 座椅接口
 */
public interface Seat {
	void massage();
}

/**  
 * 高端座椅 实现
*/
class LuxurySeat implements Seat{
	@Override
	public void massage() {
		System.out.println("自动按摩.....");
	}
}
/**   
 * 低端座椅实现
*/
class LowSeat implements Seat{
	@Override
	public void massage() {
		System.out.println("不能自动按摩.....");
	}
}
/**
 * 轮胎接口
 */
public interface Tyre {
	void revolve();
}

/**
 * 高端轮胎实现
 */
class LuxuryTyre implements Tyre{
	@Override
	public void revolve() {
		System.out.println("高端转的就是好.....");
	}
}

/**
 * 低端轮胎实现
 */
class LowTyre implements Tyre{
	@Override
	public void revolve() {
		System.out.println("高端转的就是好.....");
	}
}
public interface CarFactory1 {
	Engine createEngine();
	Seat createSeat();
	Tyre createTyre();
}

/**
 * 高端汽车
 */
class LuxuryCarFactory implements CarFactory1{
	@Override
	public Engine createEngine() {
		return new LuxuryEngine();
	}
	@Override
	public Seat createSeat() {
		return new LuxurySeat();
	}
	@Override
	public Tyre createTyre() {
		return new LuxuryTyre();
	}
}
/**
 * 低端汽车
 */
class LowCarFactory implements CarFactory1{
	@Override
	public Engine createEngine() {
		return new LowEngine();
	}
	@Override
	public Seat createSeat() {
		return new LowSeat();
	}
	@Override
	public Tyre createTyre() {
		return new LowTyre();
	}
}

class Test{
	public static void main(String[] args) {
		CarFactory1 carFactory=new LuxuryCarFactory();
		Engine createEngine = carFactory.createEngine();
		Seat createSeat = carFactory.createSeat();
		Tyre createTyre = carFactory.createTyre();
	}
}

三:建造者模式

1.场景:我们要建造一个复杂的产品。比如:神州飞船,iphone。这个复杂的产品的创建,装配这些子组件需要有个步骤问题,实际开发中,我们所需要的对象构建时,也非常复杂,有很多步骤需要处理时。

2.建造模式的本质

  • 分离了对象子组件的单独构造(由Builder来负责)和装配(由Director负责)。 从而可以构 造出复杂的对象。这个模式适用于:某个对象的构建过程复杂的情况下使用。
  • 由于实现了构建和装配的解耦。不同的构建器,相同的装配,也可以做出不同的对象; 相同的构建器,不同的装配顺序也可以做出不同的对象。也就是实现了构建算法、装配 算法的解耦,实现了更好的复用。

3.构建彭大坤的宇宙飞船

/**   
 * 宇宙飞船类
*/
public class AirShip {
	private OrbitalModul orbitalModul;//轨道仓模块
	private Engine engine;//发动机模块
	private EscapeTower escapeTower;//逃逸塔模块
	public void launch(){
		System.out.println(orbitalModul.getName());
		System.out.println(engine.getName());
		System.out.println(escapeTower.getName());
	}
	//get  set
}
class OrbitalModul{
	private String name;
	//构造方法 get set
}
class Engine{
	private String name;
	//构造方法 get set
}

class EscapeTower{
	private String name;
	//构造方法 get set
}
/**
 * 构建接口
 */
public interface AirShipBuild {
	Engine bulidEngine();
	OrbitalModul buildOrbitalModul();
	EscapeTower buildEscapeTower();
}
/**
 * 组装接口
 */
public interface AirShipDirector {
	AirShip directorAirShip();
}
/**
 * 构建彭大坤的飞船
 */
public class PDKAirShipBuild implements AirShipBuild {
	@Override
	public Engine bulidEngine() {
		return new Engine("bulid PDKEngine......");
	}
	@Override
	public OrbitalModul buildOrbitalModul() {
		return new OrbitalModul("build PDKOrbitalModul......");
	}
	@Override
	public EscapeTower buildEscapeTower() {
		return new EscapeTower("build PDKEscapeTower.......");
	}
}
/**
 * 彭大坤的宇宙飞船装配实现
 */
public class PDKAirShipDirector implements AirShipDirector{
	private AirShipBuild airShipBuild;
	public PDKAirShipDirector(AirShipBuild airShipBuild) {
		super();
		this.airShipBuild = airShipBuild;
	}
	@Override
	public AirShip directorAirShip() {
		AirShip airShip = new AirShip();
		airShip.setEngine(airShipBuild.bulidEngine());
		airShip.setEscapeTower(airShipBuild.buildEscapeTower());
		airShip.setOrbitalModul(airShipBuild.buildOrbitalModul());
		return airShip;
	}
	
	//测试建造飞船,并起飞
	public static void main(String[] args) {
		AirShipBuild airShipBuild = new PDKAirShipBuild();
		AirShipDirector airShipDirector = new PDKAirShipDirector(airShipBuild);
		AirShip airShip = airShipDirector.directorAirShip();
		airShip.launch();
	}
}

4.适用场景:构建的对象比较复杂,需要不同的组装就可以使用建造者模式

  • StringBuilder类的append方法
  • SQL中的PreparedStatement
  • JDOM中,DomBuilder、SAXBuilder

四:原型模式(prototype)

1.场景:思考一下:克隆技术是怎么样的过程? 克隆羊多利大家还记得吗?javascript语言中的,继承怎么实现?那里面也有prototype,大家还记得吗?

2.原型模式:

  • 通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。
  • 就是java中的克隆技术,以某个对象为原型,复制出新的对象。显然,新的对象具备原型对象的特点
  • 优势有:效率高(直接克隆,避免了重新执行构造过程步骤) 。
  • 克隆类似于new,但是不同于new。new创建新的对象属性采用的是默认值。克隆出的 对象的属性值完全和原型对象相同。并且克隆出的新对象改变不会影响原型对象。然后, 再修改克隆对象的值。

3.实现:

  • Cloneable接口和clone方法
  • Prototype模式中实现起来最困难的地方就是内存复制操作,所幸在Java中提供了 clone()方法替我们做了绝大部分事情。

4.原型模式浅复制

/**
 * 克隆羊,浅克隆
 */
public class Sheep implements Cloneable{

	private String name;
	private Date birthday;
	
	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object clone = super.clone();//调用Object的clone方法
		return clone;
	}

	//全参构造,get,set
	
	public static void main(String[] args) throws CloneNotSupportedException {
		Date date = new Date(131313131232L);
		Sheep sheep = new Sheep("多利的父本",date);
		System.out.println(sheep.getName());
		System.out.println(sheep.getBirthday());
		//改变时间
		date.setTime(1531343132542L);
		Sheep clone = (Sheep) sheep.clone();//克隆对象
		clone.setName("多利");
		System.out.println(clone.getName());
		System.out.println(clone.getBirthday());//时间变了
		System.out.println(sheep.getBirthday());//时间也变了,说明克隆时,只是克隆了sheep对象,并没有克隆其中的Date对象,sheep与clone的date对象指向一个,这就是浅克隆
	}
	
}

5.原型模式深复制

/**
 * 克隆羊,深克隆
 */
public class Sheep2 implements Serializable{

	private String name;
	private Date birthday;
	
	//全参构造,get,set

	public static void main(String[] args) throws Exception {
		Date date = new Date(15543456121313L);
		Sheep2 sheep2 = new Sheep2("多利的父本", date);
		System.out.println(sheep2.getName());
		System.out.println(sheep2.getBirthday());
		
		//序列化
		ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
		ObjectOutputStream outputStream = new ObjectOutputStream(byteArrayOutputStream);
		outputStream.writeObject(sheep2);
		byte[] byteArray = byteArrayOutputStream.toByteArray();//对象读到byte数组中
		outputStream.close();
		byteArrayOutputStream.close();
		//反序列化
		ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArray);
		ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
		Sheep2 readObject = (Sheep2) objectInputStream.readObject();//克隆出新独享
		objectInputStream.close();
		byteArrayInputStream.close();
		
		date.setTime(1542154785112L);//修改时间
		System.out.println(readObject.getName());
		System.out.println(readObject.getBirthday());//克隆出的对象时间不变
		System.out.println(sheep2.getBirthday());//原对象时间变了,所以对象中data对象也被克隆了一份
	}
	
}

6.原型模式好处:短时间大量创建对象,当创建对象很耗时时,通过原型模式克隆出对象性能要好于new。原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone 的方法创建一个对象,然后由工厂方法提供给调用者。spring中bean的创建实际就是两种:单例模式和原型模式。(当然,原型模式需要和工厂模式搭配起来)

五:适配器模式(adapter)

1.什么是适配器模式:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。

2.模式中的角色:

  • 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象 的类,也可以是接口。
  • 需要适配的类(Adaptee):需要适配的类或适配者类。
  • 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成 目标接口。

3.案例:

/**
 * 被适配的类,键盘
 */
public class Adaptee {
	/**
	 * 打字请求
	 */
	public void request(String key){
		System.out.println(key+"...........");
	}
}
/**
 * 适配器接口
 */
public interface Target {
	void handleRequest(String key);
}
/**
 * 适配器,类适配器模式,缺点不可多继承
 */
public class Adapter extends Adaptee implements Target {
	@Override
	public void handleRequest(String key) {
		this.request(key);
	}
}
/**
 * 适配器,组合适配器模式
 */
public class Adapter2 implements Target {
	private Adaptee adaptee;
	
	public Adapter2(Adaptee adaptee) {
		super();
		this.adaptee = adaptee;
	}
	@Override
	public void handleRequest(String key) {
		adaptee.request(key);
	}
}
/**
 * 客户端请求,笔记本,笔记本需要适配键盘
 */
public class Client {
	
	public void test(Target target){
		target.handleRequest("public static void main(String[] args)");
	}
	public static void main(String[] args) {
		Client client = new Client();
		Adaptee adpatee = new Adaptee();
		Target adapter = new Adapter();
		client.test(adapter);
		Target adapter2 = new Adapter2(adpatee);
		client.test(adapter2);
	}

}

适配器有类适配器和组合适配器两种形式,通常使用组合适配器。

4.工作中的场景

  • 经常用来做旧系统改造和升级
  • 如果我们的系统开发之后再也不需要维护,那么很多模式都是没必要 的,但是不幸的是,事实却是维护一个系统的代价往往是开发一个系统的数倍。

六:代理模式

1.核心作用:通过代理,控制对对象的访问,可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后 做后置处理。(即:AOP的微观实现)

2.核心角色:

  • 抽象角色:定义代理角色和真实角色的公共对外方法
  • 真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑, 供代理角色调用。关注真正的业务逻辑!
  • 代理角色:实现抽象角色,是真实角色的代理,通过真实角色 的业务逻辑方法来实现抽象方法,并可以附加 自己的操作。将统一的流程控制放到代理角色中处理!

3.应用场景:

  • 安全代理:屏蔽对真实角色的直接访问。
  • 远程代理:通过代理类处理远程方法调用(RMI)
  • 延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。

4.代理分类:

  • 静态代理
  • 动态代理(JDK自带的动态代理,javaassist字节码操作库实现,CGLIB代理,ASM(底层使用指令,可维护性较差))

5.静态代理:

/**
 * 明星接口
 */
public interface Star {
	//面谈
	void confer();
	//签合同
	void signContract();
	//订票
	void bookTicket();
	//唱歌
	void sing();
	//收钱
	void collectMoney();
}
/**
 * 真实的明星
 */
public class RealStar implements Star {
	@Override
	public void confer() {
		System.out.println("confer..........");
	}
	@Override
	public void signContract() {
		System.out.println("signContract..........");
	}
	@Override
	public void bookTicket() {
		System.out.println("bookTicket..........");
	}
	@Override
	public void sing() {
		System.out.println("sing..........");
	}
	@Override
	public void collectMoney() {
		System.out.println("collectMoney..........");
	}
}
/**
 * 代理明星,相当于经纪人,除了不能唱歌,其他都能干
 * 静态代理,生成字节码对象后,代理关系就确定了
 */
public class ProxyStar implements Star {
	
	private Star star;
	
	//传递需要被代理的对象
	public ProxyStar(Star star) {
		super();
		this.star = star;
	}
	@Override
	public void confer() {}
	@Override
	public void signContract() {}
	@Override
	public void bookTicket() {}
	@Override
	public void sing() {
		//在明星唱歌前后经纪人可以干点其他的事,在Spring的AOP中这叫前置通知或后置通知,可以对被代理对象进行功能增强
		System.out.println("经纪人在明星唱歌前检查一下音响.......");
		star.sing();
		System.out.println("经纪人在明星唱歌完后帮忙起哄鼓掌.......");
	}
	@Override
	public void collectMoney() {}
	
	public static void main(String[] args) {
		Star realStar = new RealStar();
		ProxyStar proxyStar = new ProxyStar(realStar);
		proxyStar.sing();
	}

}

静态代理在字节码生成后代理关系就确定了。

6.动态代理(JDK自带动态代理)

public class StarHandler implements InvocationHandler {
	Star realStar;
	public StarHandler(Star realStar) {
		super();
		this.realStar = realStar;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("经纪人在明星唱歌前检查一下音响.......");
		//调用目标方法,传入要被代理的对象及方法参数
		Object invoke = method.invoke(realStar, args);
		System.out.println("经纪人在明星唱歌完后帮忙起哄鼓掌.......");
		return invoke;
	}
	public static void main(String[] args) {
		Star star = new RealStar();
		StarHandler starHandler = new StarHandler(star);
		//创建代理对象
		Star object = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Star.class}, starHandler);
		//通过代理对象调用目标对象的目标方法
		object.sing();
	}
}

动态代理在字节码生成时代理对象与被代理对象之间关系不确定,只有在运行期间动态创建代理对象,JDK自带代理,需要被代理对象有实现接口,否者无法创建代理对象,CgLib代理则不需要。

7.应用场景:spring中AOP的实现,struts2中拦截器的实现,– Hibernate中延时加载的实现.........

更多推荐

设计模式详解(一)