java常用设计模式学习总结

1.单例模式

应用场景:顾名思义,自始至终都操作的是同一个对象的时候,需要用单例模式

​/**
 * 单例懒汉式(比较常用)
 */
public class SingletonPatternLazy {
	
	private static SingletonPatternLazy singletonPattern = null;
	
    //私有构造
	private SingletonPatternLazy(){}
	
	//获取实例
	public static SingletonPatternLazy getInstance(){
		return SingletonPatternInstance.SingletonPatternLazy;
	}

	//内部类中初始化SingletonPatternLazy的实例
	private static class SingletonPatternInstance {	
		private final static SingletonPatternLazy singletonPattern = new SingletonPatternLazy();		
	}
	
}

/**
 * 单例饿汉式(没什么用,知道有就行了)
 */
public class SingletonPattern {
	
    //初始化实例
	private final static SingletonPattern singletonPattern = new SingletonPattern();
	
    //私有构造
	private SingletonPattern(){}
	
    //获取实例
	public static SingletonPattern getInstance(){
		return singletonPattern;
	}
	
}

//main方法测试
public static void testSingletonPattern(){

	//线程1获取一次实例并打印
    Thread thread1 = new Thread(new Runnable() {			
		public void run() {
			SingletonPatternLazy instance = SingletonPatternLazy.getInstance();
			System.out.println(instance);
		}
	});
	
	//线程2获取一次实例并打印
	Thread thread2 = new Thread(new Runnable() {			
		public void run() {
			SingletonPatternLazy instance = SingletonPatternLazy.getInstance();
			System.out.println(instance);
		}
	});
		
	thread1.start();
	thread2.start();
		
}

这里有一个小小的误区:

/**
 * 单例懒汉式(这种方式有bug)
 */
public class SingletonPatternLazy {
    
    private static SingletonPatternLazy singletonPattern = null;
    
    //私有构造
    private SingletonPatternLazy(){}
    
    //同步获取实例
    private static synchronized SingletonPatternLazy newInstance(){
        return new SingletonPatternLazy();
    }
    
    //如果为实例null才同步获取实例
    public static SingletonPatternLazy getInstance(){
        if(singletonPattern == null){
            singletonPattern = newInstance();
        }
        return singletonPattern;
    }
    
}

上述代码也是一种单例模式,bug就在于,如果在同步获取实例的时候,有一个比较耗时的操作,那么会导致第二个线程进来的时候,第一个线程的singletonPattern 仍然未获取到实例,因此会去新获取一个实例,存在线程安全,这种方法正确的写法是:

/**
 * 单例懒汉式(最标准的单例模式)
 */
public class SingletonPatternLazy {
	
	private static SingletonPatternLazy singletonPattern = null;
	
    //私有构造
	private SingletonPatternLazy(){}
	
	
    //如果为实例null才同步获取实例
	public static synchronized SingletonPatternLazy getInstance(){
		if(singletonPattern == null){
			singletonPattern = new SingletonPatternLazy();
		}
		return singletonPattern;
	}
	
}

但这种方式在多线程环境下每次获取实例的时候都同步执行,效率低,不推荐

2.工厂方法模式

应用场景:

当我们需要获取同一规范下的各个不同实现的对象,并且再获取这些对象的时候比较麻烦的情况下,可以考虑使用工厂模式。

在扩展规范的实现的时候,同时又需要去扩展工厂,为了便于扩展,适应于开闭原则,因此产生了工厂方法模式,即一个工厂只创建规范下的一个实现的对象。

不同的对象的创建对应不同的工厂,那么这些不同的工厂就可以抽象出一个模板出来,或者提前定义一个接口出来。

​
/*
 * 需要被使用工厂创建的source
 */
//Person规范
public interface Person {	
	void work();
}

//Person的一个具体实现,Man
public class Man implements Person {
	
	private Man(){}

	public void work() {
		System.out.println("Man work...");
	}

}

//Person的一个具体实现,Women
public class Women implements Person {

	private Women(){}
	
	public void work() {
		System.out.println("Women work...");
	}

}

/*
 * 工厂相关
 */
//工厂规范
public interface PersonFactory {
	
	Person getInstance() throws Exception;
	
}

//工厂规范的一个实现ManFactory
public class ManFactory implements PersonFactory {
	
	private final String CLASSFORNAME = "cn.qu.factorymethod.po.Man";
	
	private Man man = null;
	
	//同步获取Man的实例,之所以用同步是因为融入了单例模式
	public synchronized Man getInstance() throws Exception {
		if(man == null){
			@SuppressWarnings("unchecked")
			Class<Man> forName = (Class<Man>) Class.forName(CLASSFORNAME);
			Constructor<Man> declaredConstructor = forName.getDeclaredConstructor();
			declaredConstructor.setAccessible(true);
			man = declaredConstructor.newInstance();
		}
		return man;
	}

}

//工厂规范的一个实现WomenFactory
public class WomenFactory implements PersonFactory {
	
	private final String CLASSFORNAME = "cn.qu.factorymethod.po.Women";
	
	private Women women = null;
	
	public synchronized Women getInstance() throws Exception {
		if(women == null){
			@SuppressWarnings("unchecked")
			Class<Women> forName = (Class<Women>) Class.forName(CLASSFORNAME);
			Constructor<Women> declaredConstructor = forName.getDeclaredConstructor();
			declaredConstructor.setAccessible(true);
			women =  declaredConstructor.newInstance();
		}
		return women;
	}

}

/*
 * 工厂方法模式测试
 */
public static void testFactoryMethod() {
	try{
		final ManFactory manFactory = new ManFactory();

		final WomenFactory womenFactory = new WomenFactory();

		
		Thread thread1 = new Thread(new Runnable() {
			
			public void run() {					
				try {
					Man man = manFactory.getInstance();
					System.out.println("thread1.man:" + man);
					Women women = womenFactory.getInstance();
					System.out.println("thread1.women:" + women);
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		});
		
		Thread thread2 = new Thread(new Runnable() {
			
			public void run() {					
				try {
					Man man = manFactory.getInstance();
					System.out.println("thread2.man:" + man);
					Women women = womenFactory.getInstance();
					System.out.println("thread2.women:" + women);
				} catch (Exception e) {
					e.printStackTrace();
				} 
			}
		});
		
		thread1.start();
		thread2.start();
		
	}catch (Exception e) {
		e.printStackTrace();
	}
}

​

3.静态代理模式

应用场景:用的不太多,一般用动态代理

//被代理的规范
public interface IPerson {
	void doSome();
}

//被代理的实现
public class Person implements IPerson{
	
	public void doSome(){
		System.out.println("基本功能...");
	}
	
}

//代理类
public class PersonProxy implements IPerson{
	
	private IPerson person;
	
    //构造需要一个被代理的对象
	public PersonProxy(IPerson person){
		this.person = person;
	}
	
	public void doSome(){
		before();
		person.doSome();
		after();
	}
	
	public void before(){
		System.out.println("before...");
	}
	
	public void after(){
		System.out.println("after...");
	}
}

/*
 *测试静态代理
 */
public static void testProxy(){
	IPerson proxy = new PersonProxy(new Person());
	proxy.doSome();
}

4.动态代理模式

应用场景:spring的aop底层就是基于动态代理,当我们需要横向且动态对程序进行扩展,即扩展任意对象的方法的时候,可以用到动态代理

//被代理规范
public interface ISource {
	void doSome(String inputSome);
}

//被代理的实现
public class SourceImpl implements ISource{
	
	public void doSome(String inputSome){
		System.out.println("基本功能,输出内容:" + inputSome);
	}
	
}

//创建一个简单的代理内容的实现类
public class BeforeAfterInvocationHandler implements InvocationHandler {
	
	private Object source;

	public BeforeAfterInvocationHandler(Object source){
		this.source = source;
	}
	
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		before();
		method.invoke(source, args);
		after();
		return null;
	}
	
	
	public void before(){
		System.out.println("------执行before-------");
	}
	
	public void after(){
		System.out.println("------执行after-------");
	}
	
	/**
	 * 获取t对象的代理对象
	 * @param t 被代理的对象
	 * @return 返回代理对象
	 */
	@SuppressWarnings("all")
	public static <T> T getProxy(T t){
		BeforeAfterInvocationHandler invocationHandler = new BeforeAfterInvocationHandler(t);
		Class[] interfaces = t.getClass().getInterfaces();
		T tProxy = (T) Proxy.newProxyInstance(invocationHandler.getClass().getClassLoader(), interfaces, invocationHandler);
		return tProxy;
	}
	
}

//测试动态代理
public static void testDynamicProxy(){
	ISource source = new SourceImpl();
	BeforeAfterInvocationHandler.getProxy(source).doSome("这是动态代理测试的输出内容");
}

5.装饰者模式

应用场景:当我们需要动态的横向扩展程序的时候,即动态的扩展某一对象的方法,可以用装饰者模式

注意与动态代理的区别:

动态代理是对任意对象的方法扩展,但扩展的内容是固定不变的

装饰者模式是对某一个对象的方法扩展,扩展的内容是可以动态变化的

//被装饰的规范
public interface IPerson {
	void doSome();
}

//被装饰规范的实现
public class PersonImpl implements IPerson {

	public void doSome() {
		System.out.println("吃饭功能....");
	}

}

//抽象装饰器
public abstract class PersonDecorator implements IPerson {
	
	private IPerson person;
	
	public PersonDecorator(IPerson person){
		this.person = person;
	}
	
	//调用当前构造中接受的person实例的dosome()
	public void doSome() {
		person.doSome();
	}

}

//装饰器Student
public class Student extends PersonDecorator {
	
	//构造需要提供一个person实例
	public Student(IPerson person){
		//把构造参数交给父类
		super(person);
	}
	
	public void doSome(){

		/*
		 *首先,调用父类的doSome()
		 *然后,父类中又调用当前构造中接受的person实例的dosome()
		 */
		super.doSome();
		System.out.println("学习功能...");
	}
}

//装饰器Worker
public class Worker extends PersonDecorator {
	
	public Worker(IPerson person){
		super(person);
	}
	
	public void doSome(){
		super.doSome();
		System.out.println("工作功能...");
	}

}

//测试装饰者模式
public static void testDecorator(){
	//基本的person
	PersonImpl person = new PersonImpl();
	System.out.println("--------------person: --------------");
	//基本的person所做的事
	person.doSome();

	//被worker装饰过的基本person
	Worker worker = new Worker(person);
	System.out.println("--------------worker: --------------");
	//被worker装饰过的person所做的事
	worker.doSome();

	//被学生装饰过的worker
	Student student = new Student(worker);
	System.out.println("--------------student: --------------");
	//被学生装饰过的worker所做的事
	student.doSome();
}

6.适配器模式

6.1类适配

应用场景:比如应用中有一个类A,还有一个规范B,且规范B的某一个或多个方法具有和类A相同的实现,因此就不需要再单独去实现这些方法了,可以新增一个规范B的适配器类C,直接去继承类A,然后再实现规范B剩下的方法(当然前提是不去让类A直接实现规范B)

//适配的类型SourceCamera
public class SourceCamera {
	
	public void photograph(){
		System.out.println("拍照功能...");
	}
	
}

//被适配的规范IPhone
public interface IPhone {
	
	public void call();
	
	public void photograph();
}

//适配器PhoneAdapter
public class PhoneAdapter extends SourceCamera implements IPhone {
	
	public void call() {
		System.out.println("打电话功能...");
	}

}

//测试适配器模式(适配类)
public static void testAdapter() {
	IPhone phone = new PhoneAdapter();
	phone.call();
	phone.photograph();
}

6.2对象适配

应用场景:与上述类似,只是类A中的方法与规范B中方法的声明不同,但是同时还想让规范B具有类A的功能,那么可以新增一个规范B的适配器类C,在构造类C的时候,把类A的对象传进来,在类C中调用类A的相关方法

//适配的类型SourceCamera
public class SourceCamera {
	
	public void paizhao(){
		System.out.println("拍照功能...");
	}
	
}

//被适配的规范IPhone
public interface IPhone {
	
	public void call();
	
	public void photograph();
}

//适配器PhoneAdapter
public class PhoneAdapter implements IPhone {
	
	private SourceCamera camera;
	
	public PhoneAdapter(){}
	
	public PhoneAdapter(SourceCamera camera){
		this.camera = camera;
	}
	
	public void call() {
		System.out.println("打电话功能...");
	}

	public void photograph() {
		camera.paizhao();
	}

}

//测试适配器模式(适配对象)
public static void testAdapter() {
	IPhone phone = new PhoneAdapter(new SourceCamera());
	phone.call();
	phone.photograph();
}

6.3接口适配

应用场景:如果需要分别实现规范中的方法,可以使用这种模式

//被适配的规范
public interface IPhone {
	
	public void call();
	
	public void photograph();
	
	public void music();
	
	public void sendMsg();
}

//抽象适配器
public abstract class PhoneAdapter implements IPhone {

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

	public void photograph(){}

	public void music(){}

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

}

//适配的类型MiPhone
public class MiPhone extends PhoneAdapter{
	
	@Override
	public void photograph() {
		System.out.println("MiPhone.photograph...");
	}
	
}

//适配的类型VivoPhone
public class VivoPhone extends PhoneAdapter {

	@Override
	public void music() {
		System.out.println("VivoPhone.music...");
	}
	
}

//测试接口适配
public static void testAdapter() {
	IPhone miPhone = new MiPhone();
	miPhone.call();
	miPhone.photograph();
	IPhone vivoPhone = new VivoPhone();
	vivoPhone.sendMsg();
	vivoPhone.music();
}

7.桥接模式

应用场景:当我们需要操作规范,但又无法固定实现的时候,可以提供一组规范,让客户方来实现,我们操作的时候只需注入客户方的实现对象,这种模式就是桥接模式,例如:jdbc定义了驱动规范,各个数据库厂商提供不同的驱动实现

//需要桥接的规范IBridgeAble
public interface IBridgeAble {	
	public void doSome(String arg0, String arg1);	
}

//定义对该规范的伪实现BridgeAble
public class BridgeAble implements IBridgeAble {
	
	private IBridgeAble bridgeAble;
	
	public BridgeAble(IBridgeAble bridgeAble){
		this.bridgeAble = bridgeAble;
	}

	public void doSome(String arg0, String arg1) {	
		bridgeAble.doSome(arg0, arg1);
	}

}

//A客户方提供的实现BrideAbleImplA
public class BrideAbleImplA implements IBridgeAble{

	public void doSome(String arg0, String arg1) {
		System.out.println("BrideAbleImplA.arg0: " + arg0 + " BrideAbleImplA.arg1: " + arg1);
	}

}

//B客户方提供的实现BrideAbleImplB
public class BrideAbleImplB implements IBridgeAble{

	public void doSome(String arg0, String arg1) {
		System.out.println("BrideAbleImplB.arg0: " + arg0 + " BrideAbleImplB.arg1: " + arg1);
	}

}

//测试桥接模式
public static void testBridge(){
	BridgeAble bridge = new BridgeAble(new BrideAbleImplA());
	bridge.doSome("A", "A1");
}

8.观察者模式

应用场景:观察者模式略微难理解,但十分重要,例如监听器就需要使用观察者模式来实现

//定义观察者规范
public interface IObserver {	
	public void operate();	
}

//观察者ObserverOne,额外提供了单例模式获取对象,通常情况观察者,都是单例的
public class ObserverOne implements IObserver{	

	private ObserverOne(){}
	
	public void operate() {
		System.out.println("观察者1观察到了变化");
	}
	
	public static ObserverOne getInstance(){
		return GetInstance.object;
	}
	
	private static class GetInstance{
		private final static ObserverOne object = new ObserverOne();		
	}

}

//观察者ObserverTwo
public class ObserverTwo implements IObserver{

	public ObserverTwo(){}
	
	public void operate() {
		System.out.println("观察者2观察到了变化");
	}
	
	public static ObserverTwo getInstance(){
		return GetInstance.object;
	}
	
	static class GetInstance{
		private final static ObserverTwo object = new ObserverTwo();		
	}

}

//抽象的观察对象BeObserver
public abstract class BeObserver {
	
	private Set<IObserver> observers = new HashSet<IObserver>();
	
	//添加观察者
	public void addObserver(IObserver observer){
		observers.add(observer);
	}
	
	//删除观察者
	public void removeObserver(IObserver observer){
		observers.remove(observer);
	}
	
	//通知所有观察者
	public void notifyObservers(){
		for (IObserver observer : observers) {
			observer.operate();
		}
	}
	
	public abstract void doSome();
}

//观察的对象BeObserverImpl
public class BeObserverImpl extends BeObserver{

	@Override
	public void doSome() {
		boolean isNotify = false;
		
		//执行一段逻辑后判断,是否需要通知观察者
		isNotify = true;
		if(isNotify){
			//通知所有的观察者
			super.notifyObservers();
		}
	}

}

//测试观察者模式
public static void testObserver(){
	//构建一个观察对象
	BeObserver beObserver = new BeObserverImpl();
	//添加观察者
	beObserver.addObserver(ObserverOne.getInstance());
	beObserver.addObserver(ObserverTwo.getInstance());
	//观察对象做了一些事情,并被观察者观察到
	beObserver.doSome();
}

猜你喜欢

转载自blog.csdn.net/m0_37414960/article/details/81080665