一 设计模式在总体上分为三类:
二 单例模式
主要模式:
(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)总结:
好了,我们上述的单例模式、工厂模式、建造者模式、原型模式都统称为创建型模式,下面我们来总结一下各自的特点: