常用设计模式(上)

结合原理与实例介绍以下设计模式:单例,原型,工厂方法,抽象工厂,建造者,代理五种设计模式。

1.单例模式

定义:一个类只有一个实例,且该类能自行创建这个实例的一种模式。
实际运用:Spring容器中所有bean默认是单例的java.lang.Runtime类是单例的。
适用场景:Web配置对象,各种连接池等。
注意事项:阻止对象clone, 注意线程安全问题,多重类加载器也会破坏单例,序列化。

public class Runtime {
    private static Runtime currentRuntime = new Runtime();
    public static Runtime getRuntime() {
        return currentRuntime;
    }
    private Runtime() {}
}

实例:单例分为饿汉和懒汉模式。
饿汉:

public class SingleBean {
	private static final SingleBean INSTANCE = new SingleBean();
	private SingleBean() {};//私有化构造方法
	
	public static SingleBean getInstance() {
		return INSTANCE;
	}
}

懒汉:

public class SingleBean2 {
	
	private volatile static SingleBean2 INSTANCE = null;//需要有volatile修饰,保证多线程可见性
	
	private SingleBean2() {};

	//减少锁粒度
	public static  SingleBean2 getInstance() {
		if(INSTANCE == null) {
			synchronized (SingleBean2.class) {
				if(INSTANCE == null) {
					INSTANCE = new SingleBean2();
				}
			}
		}
		return INSTANCE;
	}
}

实现单例还有一些其它方式:枚举私有静态内部类

	private static class Single{
		private static final SingleBean2 INSTANCE = new SingleBean2();
	}

2.原型模式

定义:用一个已经创建的实例作为原型,通过复制该原型对象来创建一个和原型相同或相似的新对象。
实际运用:Java中Object类提供了clone方法(浅拷贝),java.lang.Cloneable方法

 protected native Object clone() throws CloneNotSupportedException;

适用场景:对象之间相同或相似,即只是个别的几个属性不同的时候。或者对象创建麻烦也clone方便。
浅拷贝:复制出来的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象
深拷贝:复制出来的所有变量都含有与原来的对象相同的值,那些引用其他对象的变量将指向复制出来的新对象(将要clone的对象所引用的对象都复制了一遍)。

浅拷贝实例:clone出来student的teacher属性依然指向原Student对象的teacher属性地址。

public class Student implements Cloneable{
	
	private Integer age;
	private String name;
	private int stuNo;
	private Teacher teacher;
	
	@Override
	protected Student clone() {
		try {
			Student student = (Student) super.clone();
			return student;
		} catch (CloneNotSupportedException e) {
			e.printStackTrace();
		}
		return null;
	}
}

深拷贝实例:Teacher需要实现Serializable接口

public class Student2 implements Serializable{
	private static final long serialVersionUID = 1L;
	private Integer age;
	private String name;
	private int stuNo;
	private Teacher teacher;
	
	public Student2 clone() {//必须实现Serializable接口
		 try {
			 ByteArrayOutputStream bo = new ByteArrayOutputStream();
		     ObjectOutputStream oo = new ObjectOutputStream(bo);
		     oo.writeObject(this);
		     
		     ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
		     ObjectInputStream oi = new ObjectInputStream(bi);
		     Student2 student2 = (Student2) oi.readObject();
		     return student2;
		} catch (Exception e) {
			e.printStackTrace();
		}
		 return null;
	}
}

3. 工厂方法和抽象工厂模式

工厂方法:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中(当创建的产品就一个类别时,可退化为简单工厂模式→Spring BeanFactory)。

抽象工厂模式:为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
看了上面的概率是不是觉得有点抽象

工厂方法实例
有汽车工厂生产汽车,汽车有不同的品牌,对应品牌的工厂才能生产对应品牌的汽车。

// 汽车工厂
public interface CarFactory {
	Car createCar();
}
public abstract class Car {
	abstract void show();
}

宝马工厂:

public class BMWFactory implements CarFactory{
	@Override
	public Car createCar() {
		return new BMWCar();
	}
}
public class BMWCar extends Car{
	@Override
	void show() {
		System.out.println("BMWCar show...");
	}
}

本田工厂:

public class HFactory implements CarFactory{
	@Override
	public Car createCar() {
		return new HCar();
	}
}
public class HCar extends Car{
	@Override
	void show() {
		System.out.println("HCar show...");
	}
}

具体测试:

public class Test {
	public static void main(String[] args) {
		//客户不需要知道具体的产品名,只需要知道对应的工厂即可
		CarFactory bmwFactory = new BMWFactory();
		bmwFactory.createCar().show();
		CarFactory hFactory = new HFactory();
		hFactory.createCar().show();
	}
}

抽象工厂实例
工厂能生产一类产品,比如电脑,手机,平板电脑,依然对应不同的品牌(小米,华为,苹果),对应品牌的工厂能生成对应的电脑,手机和平板电脑。

abstract class Factory {
	public abstract AbstractProduct createComputer();
	public abstract AbstractProduct createPhone();
}
public abstract class AbstractProduct {
	public abstract void show();
}

小米工厂:

public class XiaoMiFactory extends Factory{
	private static Factory XiaoMiFactory = new XiaoMiFactory();
	public static Factory getFactory() {
		return XiaoMiFactory;
	}
	@Override
	public AbstractProduct createComputer() {
		return new XiaoMiComputer();
	}
	@Override
	public AbstractProduct createPhone() {
		return new XiaoMiPhone();
	}
}

华为工厂:

public class HuaWeiFactory extends Factory{
	private static Factory huaweiFactory = new HuaWeiFactory();
	public static Factory getFactory() {
		return huaweiFactory;
	}
	@Override
	public AbstractProduct createComputer() {
		return new HuaWeiComputer();
	}
	@Override
	public AbstractProduct createPhone() {
		return new HuaWeiPhone();
	}
}

通过实例对比:
工厂方法是:一个品牌的工厂生产一个品牌的产品
抽象工厂是:一个品牌的工厂生产一类品牌的产品

4.建造者模式

定义:将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示。
实际运用:StringBuilder , Spring的RestTemplate,ElasticSearch的Java sdk。
在我们实际运用中,我们就是导演,所以下面示例没有这个角色

实例:根据指定的配置,组装电脑

public  class Computer {

	private final String cpu;
	private final String memory;
	private final String disk;
	private final String power;

	public String getCpu() {
		return cpu;
	}

	public String getMemory() {
		return memory;
	}

	public String getDisk() {
		return disk;
	}

	public String getPower() {
		return power;
	}

	public static class Builder {
		private String cpu;
		private String memory;
		private String disk;
		private String power="超大电池";//设置属性默认值

		public Builder() {
		};

		public Builder cpu(String cpu) {
			this.cpu = cpu;
			return this;
		}

		public Builder memory(String memory) {
			//可以加入更复杂的处理逻辑
			this.memory = memory;
			return this;
		}

		public Builder disk(String disk) {
			this.disk = disk;
			return this;
		}

		public Builder power(String power) {
			this.power = power;
			return this;
		}
		public Computer build() {//检验必需属性
			if(cpu == null) {
				throw new IllegalStateException("cpu Can't be empty");
			}
			return new Computer(this);
		}
		public Builder (Computer computer) {
			this.cpu = computer.cpu;
			this.disk = computer.disk;
			this.memory = computer.memory;
			this.power = computer.power;
		}
	}
	private Computer(Builder b) {
		cpu = b.cpu;
		memory = b.memory;
		disk = b.disk;
		power = b.power;
	}
	
	public Builder newBuilder() {
		return new Builder(this);
	}

	@Override
	public String toString() {
		return "Computer [cpu=" + cpu + ", memory=" + memory + ", disk=" + disk + ", power=" + power + "]";
	}

测试:

public class Test {
	public static void main(String[] args) {
		Computer computer = new Computer.Builder().cpu("i7").disk("500G").power("超大电源").memory("500G固态").build();
		//修改属性
		Computer newComputer = computer.newBuilder().cpu("i9").build();
		System.out.println(computer);
		System.out.println(newComputer);
	}
}

5.代理模式

代理模式分为
jdk代理:实现InvocationHandler接口,加上反射机制生成代理接口的匿名实现类(基于接口生成代理类)。
cglib代理:利用ASM开源包,将代理对象类的class文件加载进来,通过修改其字节码生成子类来处理(目标类不能被final修饰)。
实际应用:很多框架底层都采用了代理,比如Spring aop,mybatis等

实例:定义一个代理工厂类,实现两种代理方式。模拟dao方法前后建立,关闭数据库连接。

public class MapperFactory {

	// jdk代理
	public static UserDao getMapper(Class<UserDao> class1) {
		try {
			UserDao userDao = (UserDao) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
					new Class[] { UserDao.class }, new UserDaoProxy());
			return userDao;
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	// cglib代理
	public static StudentDao getMapper(StudentDao target) {
		StudentDao studentDao = (StudentDao) new StudentDaoProxy().getInstance(target);
		return studentDao;
	}

}

jdk代理:

public interface UserDao {
	User   getUserById(String id); 
}

public class UserDaoProxy implements InvocationHandler {
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if ("getUserById".equals(method.getName())) {
			System.out.println("开启数据库连接");
			User user = DataBase.getUser(args[0].toString());
			System.out.println("查询完毕,关闭连接..");

			return user;
		}
		return null;
	}

}

public class User {
	
	private String id;
	private String name;
	public String getId() {
		return id;
	}
	public void setId(String id) {
		this.id = id;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public User() {
		super();
	}
	public User(String id, String name) {
		super();
		this.id = id;
		this.name = name;
	}
	@Override
	public String toString() {
		return "User [id=" + id + ", name=" + name + "]";
	}
}

/**
 * @Description:模拟从数据库查询用户
 */
public class DataBase {
	private static Map<String, User> users = new ConcurrentHashMap<String, User>();
	static{
		init();
	}
	public static User getUser(String id) {
		User user = users.get(id);
		return user;
	}
	
	private static void init() {
		for(int i=0;i<15;i++) {
			users.put(String.valueOf(i), new User(String.valueOf(i), "test"+i));
		}
	}
}

cglib代理:

public class StudentDao {

	public User getStudentById(String id) {
		System.out.println("我只负责打酱油..");
		return null;
	}
}

public class StudentDaoProxy implements MethodInterceptor {

	// 委托对象,运行时定类型
	private Object target;

	public Object getInstance(Object target) {
		this.target = target;
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(this.target.getClass());
		// 回调方法
		enhancer.setCallback(this);
		// 创建代理对象
		return enhancer.create();
	}

	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("开启连接");
		proxy.invokeSuper(obj, args);
		User user = DataBase.getUser(args[0].toString());
		System.out.println("关闭连接");
		return user;
	}
}

测试类:

public class Test {
	public static void main(String[] args) {
		// jdk动态代理
		UserDao userDao = MapperFactory.getMapper(UserDao.class);
		User user = userDao.getUserById("2");
		System.out.println(user);

		// cglib代理
		StudentDao studentDao = MapperFactory.getMapper(new StudentDao());
		User s = studentDao.getStudentById("5");
		System.out.println(s);
	}
}

参考地址:http://c.biancheng.net/view/1395.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章