设计模式GOF23之-----------创建型模式(单例模式、工厂模式、建造者模式、原型模式)

一 设计模式在总体上分为三类: 

二 单例模式 

主要模式:

(1)饿汉式:

package GOF23;
/**
 * 测试饿汉式单例模式
 * @author lenovo
 *
 */
public class SingletonErHan {
	
	//类初始化时,立即加载这个对象(没有延时加载优势)。加载类时,天然的是线程安全的!
	private static SingletonErHan instance = new SingletonErHan(); 
	
	private  SingletonErHan() {	//将构造器私有化
	}
	
	//方法没有同步,调用效率高
	public static SingletonErHan getInstance() {
		return instance;
	}
	
}

 (2)懒汉式:

package GOF23;
/**
 * 测试懒汉式单例模式(单例对象延迟加载)
 * @author lenovo
 *
 */
public class SingletonLanHan {

	//类初始化时,立即加载这个对象(延迟加载,正真用的时候再创建)
	private static SingletonLanHan s;
	private SingletonLanHan(){ //私有化构造器
	}
	
	//synchronized只允许一个线程访问,其他线程要访问只能等待(方法同步,调用效率低)
	public static synchronized SingletonLanHan getInstance() {
		if(s==null) {
			s = new SingletonLanHan();
		}
		return s;
	}
}

(3) 双重检测锁:

(4)静态内部类:

package GOF23;
/**
 * 测试静态内部类实现单例模式
 * 这种方式:线程安全,调用效率高,并且实现了延时加载!
 * @author lenovo
 *
 */
public class SingletonStaticClass {

	private static class SingletonClassInstance {
		private static final SingletonStaticClass instance = new SingletonStaticClass();
	}
	
	private SingletonStaticClass() { //构造器私有化
	}
	
	public static SingletonStaticClass getInstance() {
		return SingletonClassInstance.instance;
	}
}

 (5)枚举:

 

package GOF23;
/**
 * 测试枚举式实现单例(没有延时加载)
 * @author lenovo
 *
 */
public enum SingletonEnum {

	//这个枚举元素本身就是单例对象
	INSTANCE;
	
	//添加自己需要的操作
	public void singletonOperation() {
	}
	
	public static void main(String[] args) {
		System.out.println(SingletonEnum.INSTANCE);
	}
}

常见的五种单例模式实现方式的比较:

 

测试代码:

package GOF23;

import java.util.concurrent.CountDownLatch;

/**
 * 测试多线程环境下五种创建单例模式的效率
 * @author lenovo
 *
 */
public class Client2 {

	public static void main(String[] args) throws InterruptedException {
		
		long start = System.currentTimeMillis();
		int threadNum = 10;
		final CountDownLatch countDownLatch = new CountDownLatch(threadNum); //启动线程计数器
		
		for(int i = 0; i < threadNum; i++) { //启动10个线程
			new Thread(new Runnable() {
				@Override
				public void run() {
					for(int j = 0; j < 10000; j++) {
//						Object o = SingletonLanHan.getInstance(); //耗时17
//						Object o = SingletonErHan.getInstance(); //耗时7
//						Object o = SingletonStaticClass.getInstance(); //耗时11
						Object o = SingletonEnum.INSTANCE;  //耗时6
					}
					countDownLatch.countDown();
				}
			}).start();
		}
		
		countDownLatch.await(); //main线程阻塞, 直到线程计数器变成0,才会继续执行下去!
		long end = System.currentTimeMillis();
		System.out.println("总耗时:" + (end-start));
	}
}

 

 

如何防止反射和反序列化破解单例模式(枚举除外):

 

三 工厂模式(也可见我的另一篇文章https://blog.csdn.net/wangjian530/article/details/83621964

三种分类:

(1)简单工厂模式

接口:

package GOF23;

public interface Car {
	void run();
}

汽车的种类:

package GOF23;

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

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

创建汽车的工厂:

package GOF23;
/**
 * 简单工厂--创建汽车
 * @author lenovo
 *
 */
public class SimpleFactoryCarFactory {
	
	public static Car createAudi() {
		return new Audi();
	}
	
	public static Car createByd() {
		return new Byd();
	}

//	public static Car create(String type) {
//		if("奥迪".equals(type)) {
//			return new Audi();
//		} else if("比亚迪".equals(type)) {
//			return new Byd();
//		} else {
//			return null;
//		}
//	}
}

客户端:

package GOF23;
/**
 * 简单工厂下的客户端
 * @author lenovo
 *
 */
public class Client3 {
	
	public static void main(String[] args) {
		Car c1 = SimpleFactoryCarFactory.createAudi();
		Car c2 = SimpleFactoryCarFactory.createByd();
		c1.run();
		c2.run();
	}
}

结果:

他们之间的UML关系图:

(2)工厂方法模式

Car的抽象类接口:

package GOF23;

public interface Car {
	void run();
}

Car下面3个实现类即产品:

package GOF23;

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



package GOF23;

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


package GOF23;

public class Benz implements Car{
	@Override
	public void run() {
		System.out.println("奔弛在跑!");	
	}	
}

生产汽车的工厂的抽象类:

package GOF23;

public interface CarFactory {
	
	Car createCar();
}

 生产三种汽车的工厂:

package GOF23;

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



package GOF23;

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


package GOF23;

public class BenzFactory implements CarFactory {
	@Override
	public Car createCar() {
		return new Benz();
	}
	
	
}



在客户端我们只管调用它的方法就好了:

package GOF23;

public class Client4 {

	public static void main(String[] args) {
		Car c1 = new AudiFactory().createCar();
		c1.run();
		Car c2 = new BydFactory().createCar();
		c2.run();
		Car c3 = new BenzFactory().createCar();
		c3.run();
	}
}

下面是他们的UML模型:

简单工厂模式和工厂方法模式比较:

 (3)抽象工厂模式

 将三种产品族依次定义为接口:

引擎类:

package GOF23;

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("启动慢!");
	}
	
}

座椅类:

package GOF23;

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("不能按摩!");	
	}
}

 轮胎类:

package GOF23;

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("旋转磨损快!");
	}
}

其次就是生产汽车的工厂的接口了:

package GOF23;

public interface Car_Factory {
	Engine createEngine();
	Seat createSeat();
	Tyre createTyre();
}

 还有它下面的两个实现类:

package GOF23;

public class LuxuryCarFactory implements Car_Factory {

	@Override
	public Engine createEngine() {

		return new LuxuryEngine();
	}

	@Override
	public Seat createSeat() {
		return new LuxurySeat();
	}

	@Override
	public Tyre createTyre() {
		return new LuxuryTyre();
	}

}
package GOF23;

public class LowCarFactory implements Car_Factory {

	@Override
	public Engine createEngine() {

		return new LowEngine();
	}

	@Override
	public Seat createSeat() {
		return new LowSeat();
	}

	@Override
	public Tyre createTyre() {
		return new LowTyre();
	}

}

 客户端我们所要做的就是面向接口的编程:

package GOF23;

public class Client5 {
	
	public static void main(String[] args) {
		Car_Factory factory = new LuxuryCarFactory();
		Engine engine = factory.createEngine();
		engine.run();
		engine.start();
	}
}

工厂模式总结:

四 建造者模式 

下面我们来看一个组装飞船的例子:

飞船零件创建的接口:

package GOF23;

public interface AirShipBuilder {
	Engine1 builderEngine();
	OrbitalModule builderOrbitalModule();
	EscapeTower builderEscapeTower();
}

飞船零件创建的实现类:

package GOF23;

public class BuilderAirShip implements AirShipBuilder {

	@Override
	public Engine1 builderEngine() {
		System.out.println("构建发动机!");
		return new Engine1("发动机!");
	}

	@Override
	public OrbitalModule builderOrbitalModule() {
		System.out.println("构建轨道仓!");
		return new OrbitalModule("轨道仓!");
	}

	@Override
	public EscapeTower builderEscapeTower() {
		System.out.println("构建逃逸塔!");
		return new EscapeTower("逃逸塔!");
	}

}

 

创建飞船的方法的接口:

package GOF23;

public interface AirShipDirector { //飞船的组装的方法
	/**
	 * 组装飞船对象
	 * @return
	 */
	AirShip directAirShip(); 
	
}

创建飞船的方法的实现类:

package GOF23;

public class BuilderAirShipDirector implements AirShipDirector {

	private AirShipBuilder builder;

	public BuilderAirShipDirector(AirShipBuilder builder) {
		this.builder = builder;
	}

	@Override
	public AirShip directAirShip() {
		Engine1 e = builder.builderEngine();
		OrbitalModule o = builder.builderOrbitalModule();
		EscapeTower et = builder.builderEscapeTower();
		
		//装配成飞船对象
		AirShip ship = new AirShip();
		ship.setE(e);
		ship.setEscapeTower(et);
		ship.setOrbitalModule(o);
		return ship;
	}

}

 

飞船类:

package GOF23;

/**
 * 建造者模式--创建宇宙飞船
 * 
 * @author lenovo
 *
 */
public class AirShip {
	private OrbitalModule orbitalModule; // 轨道仓
	private Engine1 e; // 发动机
	private EscapeTower escapeTower; // 逃逸塔
	
	public void launch() {
		System.out.println("发射!");
	}

	public OrbitalModule getOrbitalModule() {
		return orbitalModule;
	}

	public void setOrbitalModule(OrbitalModule orbitalModule) {
		this.orbitalModule = orbitalModule;
	}

	public Engine1 getE() {
		return e;
	}

	public void setE(Engine1 e) {
		this.e = e;
	}

	public EscapeTower getEscapeTower() {
		return escapeTower;
	}

	public void setEscapeTower(EscapeTower escapeTower) {
		this.escapeTower = escapeTower;
	}

}

class OrbitalModule {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public OrbitalModule(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

}

class Engine1 {
	private String name;

	public void setName(String name) {
		this.name = name;
	}

	public Engine1(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

}

class EscapeTower {
	private String name;

	public EscapeTower(String name) {
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

客户端:首先我们生产飞船的零件,然后就开始组装成飞船就可以了。

package GOF23;

public class Client6 {

	public static void main(String[] args) {
		AirShipDirector director = new BuilderAirShipDirector(new BuilderAirShip());
		
		AirShip ship = director.directAirShip();
		
		System.out.println(ship.getE().getName()); //输出发动机的名字
		ship.launch();
	}
}

注意:建造者模式和工厂模式组合在一起用的情况比较多! 

五 原型模式

 

下面我将以浅克隆和深 克隆为例来举例原型模型:

(1)浅克隆(就是简单的复制出另一个对象,然后指向原来对象的地址空间)

核心代码:

@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone(); // 直接调用Object对象的clone()方法
		return obj;
	}

源代码: 

package GOF23;
/**
 * 以克隆羊多利为例操作原型模式(测试浅复制)
 */
import java.util.Date;

public class ProtoTypeSheep2 implements Cloneable {

	private String name;
	private Date birthday;

	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone(); // 直接调用Object对象的clone()方法
		return obj;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public ProtoTypeSheep2(String name, Date birthday) {
		this.name = name;
		this.birthday = birthday;
	}

	public ProtoTypeSheep2() {
		super();
	}

}
package GOF23;

import java.util.Date;

/**
 * 测试原型模式(浅克隆)
 * @author lenovo
 *
 */
public class Client7 {

	public static void main(String[] args) throws CloneNotSupportedException {
		Date date = new Date(1997L);
		ProtoTypeSheep2 s1 = new ProtoTypeSheep2("多利", date);
		ProtoTypeSheep2 s2 = (ProtoTypeSheep2) s1.clone(); //通过s1对象克隆出s2对象(浅克隆)
		
		System.out.println(s1);
		System.out.println(s1.getName() + " " + s1.getBirthday());
		//当date数值的修改会影响下面的s2的date,因为s1和s2在内存本质是指向同一段内存对象的
		date.setTime(1997530L);
		System.out.println(s1.getBirthday());
		
		
		System.out.println(s2); //但是式s2和s1是两个不同的对象
		System.out.println(s2.getName() + " " + s2.getBirthday()); //发现s1和s2里的值是一样的
		
		s2.setName("少利");
		System.out.println(s2.getName());
		
	}
}

结果:

我们发现当我们修改s1的时间时候,我们输出s2的时间也跟着改变,原因就是s1和s2指向同一个对象!

(2)深克隆(不光复制出一个对象,而且还复制出原对象的那段地址空间,也就是说一个新对象指向一段新地址空间)

核心代码:

@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone(); // 直接调用Object对象的clone()方法
		
		//添加如下的代码实现深复制(deep clone)
		ProtoTypeSheep s =  (ProtoTypeSheep) obj;
		s.birthday = (Date) this.birthday.clone(); //把属性也进行克隆
		return obj;
	}

源代码: 

package GOF23;
/**
 * 以克隆羊多利为例操作原型模式(测试浅复制)
 */
import java.util.Date;

public class ProtoTypeSheep2 implements Cloneable {

	private String name;
	private Date birthday;

	@Override
	protected Object clone() throws CloneNotSupportedException {
		Object obj = super.clone(); // 直接调用Object对象的clone()方法
		return obj;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public Date getBirthday() {
		return birthday;
	}

	public void setBirthday(Date birthday) {
		this.birthday = birthday;
	}

	public ProtoTypeSheep2(String name, Date birthday) {
		this.name = name;
		this.birthday = birthday;
	}

	public ProtoTypeSheep2() {
		super();
	}

}
package GOF23;

import java.util.Date;
/**
 * 原型模式(深克隆)
 * @author lenovo
 *
 */
public class Client8 {

	public static void main(String[] args) throws CloneNotSupportedException {
		Date date = new Date(1997L);
		ProtoTypeSheep s1 = new ProtoTypeSheep("多利", date);
		ProtoTypeSheep s2 = (ProtoTypeSheep) s1.clone(); //深克隆本质是复制出一个一模一样的对象并让s2指向它
		
		System.out.println(s1);
		System.out.println(s1.getName() + " " + s1.getBirthday());
		
		date.setTime(2211123323L);
		System.out.println(s1.getBirthday());
		

		s2.setName("少利");
		System.out.println(s2);
		System.out.println(s2.getName() + " " + s2.getBirthday());
		
	}
}

结果:

我们发现当s1时间修改并不影响s2的时间,s2的时间还和克隆s1时的时间一样,这就是深复制!

(3)我们还可以使用序列化和反序列化实现深克隆

核心代码:

//使用序列化和反序列化实现深克隆
		ByteArrayOutputStream bos = new ByteArrayOutputStream(); //把要输出的东西先输入到输出流中
		ObjectOutputStream oos = new ObjectOutputStream(bos); //建立输出流对象
		oos.writeObject(s1); //把要输出的东西通过输出流输出到目的地,所以是write()
		byte[] bytes = bos.toByteArray(); //再把输出的东西转化成字节数组
		
		ByteArrayInputStream bis = new ByteArrayInputStream(bytes); //把要读取的bytes先输入到输入流
		ObjectInputStream ois = new ObjectInputStream(bis); //建立读取对象
		//从输入流进行读取,所以是read()
		ProtoTypeSheep2 s2 = (ProtoTypeSheep2) ois.readObject(); //对象已经克好

源代码: 

package GOF23;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.util.Date;

import javassist.bytecode.ByteArray;

/**
 * 测试原型模式(使用序列化和反序列化实现深克隆)
 * @author lenovo
 *
 */
public class Client9 {

	public static void main(String[] args) throws CloneNotSupportedException, IOException, ClassNotFoundException {
		Date date = new Date(1997L);
		ProtoTypeSheep2 s1 = new ProtoTypeSheep2("多利", date);
		System.out.println(s1);
		System.out.println(s1.getName() + " " + s1.getBirthday());
	
		
		
		//使用序列化和反序列化实现深克隆
		ByteArrayOutputStream bos = new ByteArrayOutputStream();
		ObjectOutputStream oos = new ObjectOutputStream(bos);
		oos.writeObject(s1);
		byte[] bytes = bos.toByteArray();
		
		ByteArrayInputStream bis = new ByteArrayInputStream(bytes);
		ObjectInputStream ois = new ObjectInputStream(bis);
		
		ProtoTypeSheep2 s2 = (ProtoTypeSheep2) ois.readObject(); //对象已经克好
		
		
		
		date.setTime(1997530L);
		System.out.println("改过的时间:" + s1.getBirthday());
		
		
		System.out.println(s2); //但是式s2和s1是两个不同的对象
		System.out.println(s2.getName() + " " + s2.getBirthday()); //发现s1和s2里的值是一样的
		
		s2.setName("少利");
		System.out.println(s2.getName());
		
	}
}

我们发现结果和上面深克隆是一样的:

 

(4)总结:

 

好了,我们上述的单例模式、工厂模式、建造者模式、原型模式都统称为创建型模式,下面我们来总结一下各自的特点:

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

金州饿霸

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值