JAVA设计模式

一. 工厂模式

主要分:简单工厂、抽象工厂(多类产品即多个产品接口)、工厂方法(一类产品)模式三种,主要目的是解耦。

1. 简单工厂模式

  • 创建产品接口和产品工厂,产品实现接口
  • 工厂类通过传入类型,创建相应产品(通过接口引用接收)
    即:总工厂负责具体产品创建

(1). 产品接口

public interface Product {

	public String getPrice();
	
}

(2). 冰箱产品(实现产品接口)

public class Refrigerator implements Product {
	@Override
	public String getPrice() {
		String price = "25.23";
		System.out.println("我是冰箱,我的价格是:" + price);
		return price;
	}
}

(3). 洗衣机产品(实现产品接口)

public class WashingMachine implements Product {
	@Override
	public String getPrice() {
		String price = "99.99";
		System.out.println("我是洗衣机,我的价格是:" + price);
		return price;
	}
}

(4). 产品工厂

public class ProductFactory {

	/** 产品1-冰箱 */
	private static final int PROC_1 = 1;
	
	/** 产品2-洗衣机 */
	private static final int PROC_2 = 2;
	
	public static Product getProduct(int type) {
		if(type == PROC_1) {
			return new Refrigerator();
		} else if(type == PROC_2) {
			return new WashingMachine();
		} else {
			System.out.println("没有该类型产品...");
			return null;
		}
	}
}

(5). 测试

public class TestMain {
	
	public static void main(String[] args) {
		Product product = ProductFactory.getProduct(1);
		product.getPrice();
	}
}

(6). 输出

我是冰箱,我的价格是:25.23

2. 工厂方法模式

定义总工厂接口,各个产品自己有工厂类,工厂类实现总工厂接口的相应方法。
即:总工厂只定义方法,各个产品工厂实现总工厂方法。(工厂不负责产品创建)
使用场景:一类产品族,多个产品
(1). 总工厂类

public interface ProductFactory {

	public Product getProduct();
	
}

(2). 产品工厂

public class RefrigeratorFactory implements ProductFactory {

	@Override
	public Product getProduct() {
		return new Refrigerator();
	}
}
public class WashingMachineFactory implements ProductFactory {

	@Override
	public Product getProduct() {
		return new WashingMachine();
	}
}

(3). 测试

public class TestMain {
	
	public static void main(String[] args) {
		ProductFactory washingMachineFactory = new WashingMachineFactory();
		System.out.println(washingMachineFactory.getProduct().getPrice());
	}
}

(4). 结果

我是洗衣机,我的价格是:99.99
99.99

3. 抽象工厂模式

类似于工厂方法模式,区别在于工厂方法针对一类产品,而抽象工厂可以针对多类产品(产品的工厂提供创建多类产品的方法)。
即:产品接口新增了一个的处理过程(工厂新增一个创建新产品的方法)
场景:系统的产品多于一个产品族,而系统只消费某一族的产品。
(1). 现在产品升级了,有新产品加入,也有原来的产品,新产品接口及产品如下

public interface NewProduct {

	public String getPrice();
	
}
public class NewRefrigerator implements NewProduct {

	@Override
	public String getPrice() {
		String price = "125.23";
		System.out.println("我是新冰箱,我的价格是:" + price);
		return price;
	}
}
public class NewWashingMachine implements NewProduct {

	@Override
	public String getPrice() {
		String price = "199.99";
		System.out.println("我是新洗衣机,我的价格是:" + price);
		return price;
	}
}

(2). 现在的工厂就不止创建老产品了,也要能创建新产品(添加一个创建新产品的方法),总工厂修改如下:

public interface ProductFactory {

	public Product getProduct();
	
	public NewProduct getNewProduct();
}

(3). 自然产品工厂也要新增方法,如下

public class WashingMachineFactory implements ProductFactory {

	@Override
	public Product getProduct() {
		return new WashingMachine();
	}

	@Override
	public NewProduct getNewProduct() {
		return new NewWashingMachine();
	}
}
public class RefrigeratorFactory implements ProductFactory {

	@Override
	public Product getProduct() {
		return new Refrigerator();
	}

	@Override
	public NewProduct getNewProduct() {
		return new NewRefrigerator();
	}
}

(4). 好了,现在既可以创建新产品,也可以创建老产品,测试:

public class TestMain {
	
	public static void main(String[] args) {
		ProductFactory washingMachineFactory = new WashingMachineFactory();
		System.out.println(washingMachineFactory.getProduct().getPrice());
		System.out.println(washingMachineFactory.getNewProduct().getPrice());
	}
}

(5). 结果

我是洗衣机,我的价格是:99.99
99.99
我是新洗衣机,我的价格是:199.99
199.99

二. 适配器模式

把类的接口转变为满足要求的另一种接口,从而使因为接口不匹配无法在一起工作的两个类能够在一起工作。一般分为类适配器和对象适配器两种。

1. 类适配器(实现接口,继承类)

(1). 原始类

public class SourceClass {

	public void method1(){
		System.out.println("execute method1...");
	}
}

(2). 目标接口

public interface TargetInterface {

	public void method1();
	public void method2();
}

(3). 适配器

public class ClassAdapter extends SourceClass implements TargetInterface {

	@Override
	public void method2() {
		System.out.println("execute method2...");
	}
}

2. 对象适配器

适配器类实现目标接口,添加源类作为成员变量,并实现目标接口方法(以成员变量去实现)。
(1). 源类

public class ObjectTarget {

	public void method1 () {
		System.out.println("我只有method1方法...");
	}
}

(2). 目标接口

public interface TargetInterface {

	public void method1();
	
	// 目标类没有此方法
	public void method2();
	
}

(3). 适配器类

public class AdapterClass implements TargetInterface {

	/** 源类作为成员变量 */
	private ObjectTarget objectTarget;
	
	/**
	 * <p>创建时赋值</p>
	 * @param objectTarget
	 * @author FRH
	 * @time 2018年12月12日上午10:48:58
	 * @version 1.0
	 */
	public AdapterClass(ObjectTarget objectTarget) {
		this.objectTarget = objectTarget;
	}
	
	@Override
	public void method1() {
		// 源类去实现
		objectTarget.method1();
	}

	@Override
	public void method2() {
		System.out.println("自己去实现method2...");
	}
}

三. 代理模式

在不改变源码的情况下,实现目标对象功能的拓展。主要分静态代理、动态代理(JDK代理)和Cglib代理三种。(静态代理和动态代理的目标对象必须实现一个或多个接口,不然的话,可以用Cglib代理)

1. 静态代理

代理类实现源接口,并源接口为成员变量(在创建代理类是赋值),实现代理方法,实现中调用源接口方法共同实现。
缺点:接口层发生变化,代理类也得修改。
(1). 目标接口

public interface TargetInterface {

	public void method1();
	
}

(2). 目标实现

public class TargetImpl implements TargetInterface {

	@Override
	public void method1() {
		System.out.println("我是源实现...");
	}
}

(3). 代理类

public class ProxyClass implements TargetInterface {

	/** 源接口为成员变量 */
	private TargetInterface targetInterface;
	
	public ProxyClass(TargetInterface targetInterface) {
		this.targetInterface = targetInterface; 
	}
	
	@Override
	public void method1() {
		System.out.println("执行前工作...");
		targetInterface.method1(); // 开始执行代理方法
		System.out.println("执行后工作...");
	}
}

(4). 测试

public class TestMain {
	
	public static void main(String[] args) {
		TargetInterface target = new TargetImpl();
		ProxyClass proxyClass = new ProxyClass(target);
		proxyClass.method1();
	}
}

(5). 结果

执行前工作...
我是源实现...
执行后工作...

2. 动态代理(也称JDK代理)

运行中动态返回代理对象,调用JDK自带的Proxy类的静态方法newProxyInstance即可。
优点:不管接口怎么变,都能满足

static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h );
// ClassLoader loader:指定当前目标对象使用类加载器,写法固定
// Class<?>[] interfaces:目标对象实现的接口的类型,写法固定
// InvocationHandler h:事件处理接口,需传入一个实现类,一般直接使用匿名内部类

(1). 示例

public class TestMain {
	
	public static void main(String[] args) {
		final TargetInterface target = new TargetImpl();
		TargetInterface proxy = (TargetInterface) 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;
			}
		});
		
		proxy.method1();
	}
}

(2). 结果

执行前工作...
我是源实现...
执行后工作...

3. Cglib代理

代理的是类,不需要业务类继承接口,通过派生的子类来实现代理。通过在运行时,动态修改字节码达到修改类的目的。
前提条件:
需要引入cglib的jar文件,由于Spring的核心包中已经包括了Cglib功能,所以也可以直接引入spring-core-XXX.jar
目标类不能为final
目标对象的方法如果为final/static,那么就不会被拦截,即不会执行目标对象额外的业务方法
(1). 代理对象

public class ProxyFactory implements MethodInterceptor {

	/** 目标对象 */
	private Object target;

	public ProxyFactory(Object target) {
		this.target = target;
	}

	/**
	 * <p>给目标对象创建一个代理对象</p>
	 * @return Object 代理对象
	 * @author FRH
	 * @time 2018年12月12日上午11:26:20
	 * @version 1.0
	 */
	public Object getProxyInstance() {
		// 1.工具类
		Enhancer en = new Enhancer();
		// 2.设置父类
		en.setSuperclass(target.getClass());
		// 3.设置回调函数
		en.setCallback(this);
		// 4.创建子类(代理对象)
		return en.create();
	}

	@Override
	public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
		System.out.println("执行前工作...");
		Object returnValue = arg1.invoke(target, arg2);
		System.out.println("执行后工作...");
		return returnValue;
	}
}

(2). 测试

public class TestMain {
	
	public static void main(String[] args) {
		TargetInterface target = new TargetImpl();
		TargetImpl proxy = (TargetImpl) new ProxyFactory(target).getProxyInstance();
		proxy.method1();
	}
}

(3). 结果

执行前工作...
我是源实现...
执行后工作...

静态代理与动态代理区别:

  • 静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。
  • 静态代理事先知道要代理的是什么,而动态代理不知道要代理什么东西,只有在运行时才知道。
  • 动态代理是实现 JDK 里的 InvocationHandler 接口的 invoke 方法,但注意的是代理的是接口,也就是你的业务类必须要实现接口,通过 Proxy 里的 newProxyInstance 得到代理对象。
  • AOP编程就是基于动态代理实现的,比如著名的 Spring 框架、 Hibernate 框架等等都是动态代理的使用例子。

四. 模板方法模式

定义一个抽象类,将部分逻辑或构造方法或具体构造函数定义实现,然后定义一些抽象方法迫使子类实现剩余逻辑。这个定义好的模板提供了轮廓,子类只需要具体填充实现即可。典型使用如Servlet,doGet()和doPost()都是钩子方法(规则一般以do开头)。
(1). 模板类

public abstract class AbstractTemplate {

	/**
	 * <p>模板方法</p> void 
	 * @author FRH
	 * @time 2018年12月12日下午1:35:26
	 * @version 1.0
	 */
	public void templateMethod() {
		// 调用基本方法(具体方法)
		changelessMethod();
		
		// 子类需要实现的方法(抽象方法)
		needMethod();
		
		// 子类可变的方法(钩子方法)
		doMethod();
	}

	/**
	 * <p>子类可选择实现(钩子方法)</p> void 
	 * @author FRH
	 * @time 2018年12月12日下午1:35:48
	 * @version 1.0
	 */
	protected void doMethod() {}

	/**
	 * <p>固定方法(具体方法)</p> void 
	 * @author FRH
	 * @time 2018年12月12日下午1:35:59
	 * @version 1.0
	 */
	private final void changelessMethod() {
		System.out.println("固定方法由我实现,子类不可改变...");
	}
	
	/**
	 * <p>子类需要实现方法(抽象方法)</p> void 
	 * @author FRH
	 * @time 2018年12月12日下午1:36:25
	 * @version 1.0
	 */
	protected abstract void needMethod();
}

(2). 子实现类

public class ChildClass extends AbstractTemplate {

	@Override
	protected void needMethod() {
		System.out.println("模板要求我实现的方法...");
	}

	protected void doMethod() {
		System.out.println("我选择实现的方法(钩子方法)...");
	}
}

五. 单例模式

分法比较多,一般分懒汉模式(全局单例在第一次使用时被创建)和饿汉模式(全局单例在类加载时被创建),其它都是其变种。

1. 懒汉式写法1(只能是单线程,多线程有一定几率出现多实例,如同时进入if判断)

public class SingleModel {
	
	/** 私有的成员 */
	private static SingleModel singleModule;
	
	/**
	 * <p>私有构造</p>
	 * @author FRH
	 * @time 2018年12月12日下午1:57:37
	 * @version 1.0
	 */
	private SingleModel(){}
	
	/**
	 * <p>获取实例</p>
	 * @return SingleModel 
	 * @author FRH
	 * @time 2018年12月12日下午1:57:46
	 * @version 1.0
	 */
	public static SingleModel getSingleModel () {
		if(singleModule == null) singleModule = new SingleModel();
		return singleModule;
	}
}

2. 懒汉式写法2(在写法1上加同步锁,避免多线程访问问题,不过效率低了)

public class SingleModel {
	
	/** 私有的成员 */
	private static SingleModel singleModule;
	
	/**
	 * <p>私有构造</p>
	 * @author FRH
	 * @time 2018年12月12日下午1:57:37
	 * @version 1.0
	 */
	private SingleModel(){}
	
	/**
	 * <p>获取实例</p>
	 * @return SingleModel 
	 * @author FRH
	 * @time 2018年12月12日下午1:57:46
	 * @version 1.0
	 */
	public static synchronized SingleModel getSingleModel () {
		if(singleModule == null) singleModule = new SingleModel();
		return singleModule;
	}
}

3. 懒汉式3(锁加在对象判断为空后,继续判断,复杂)

public class SingleModel {
	
	/** 私有的成员 */
	private static SingleModel singleModule;
	
	/**
	 * <p>私有构造</p>
	 * @author FRH
	 * @time 2018年12月12日下午1:57:37
	 * @version 1.0
	 */
	private SingleModel(){}
	
	/**
	 * <p>获取实例</p>
	 * @return SingleModel 
	 * @author FRH
	 * @time 2018年12月12日下午1:57:46
	 * @version 1.0
	 */
	public static SingleModel getSingleModel () {
		if(singleModule == null) {
			synchronized(SingleModel.class) {
				if(singleModule == null) singleModule = new SingleModel();
			}
		}
		return singleModule;
	}
}

4. 懒汉式-静态内部类(建议,第一次使用时创建)

public class SingleModel {
	
	/**
	 * <p>私有构造</p>
	 * @author FRH
	 * @time 2018年12月12日下午1:57:37
	 * @version 1.0
	 */
	private SingleModel(){}
	
	/**
	 * <p>静态内部类,创建实例,第一次使用时创建</p>
	 * @author FRH
	 * @time 2018年12月12日下午2:09:02
	 * @version 1.0
	 */
	private static class SingleModelHolder {
		private final static SingleModel instance = new SingleModel();
	}
	
	/**
	 * <p>获取实例</p>
	 * @return SingleModel 
	 * @author FRH
	 * @time 2018年12月12日下午1:57:46
	 * @version 1.0
	 */
	public static SingleModel getSingleModel () {
		return SingleModelHolder.instance;
	}
}

5. 饿汉式

public class SingleModel {
	
	/** 私有的成员 */
	private static SingleModel singleModule = new SingleModel();
	
	/**
	 * <p>私有构造</p>
	 * @author FRH
	 * @time 2018年12月12日下午1:57:37
	 * @version 1.0
	 */
	private SingleModel(){}
	
	/**
	 * <p>获取实例</p>
	 * @return SingleModel 
	 * @author FRH
	 * @time 2018年12月12日下午1:57:46
	 * @version 1.0
	 */
	public static SingleModel getSingleModel () {
		return singleModule;
	}
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值