单例设计模式(SingIton)
1.饿汉式(线程安全)
- 私有化类的构造器
- 内部创建类的对象
- 要求此对象也必须声明为静态的
- 提供公共的静态的方法,返回类的对象
public class SingletonTest1 {
public static void main(String[] args) {
Bank1 bank1 = Bank1.getInstance();
Bank1 bank2 = Bank1.getInstance();
System.out.println(bank1==bank2);
}
}
//饿汉式
class Bank1 {
//1.私有化类的构造器
private Bank1() {
}
//2.内部创建类的对象
//4.要求此对象也必须声明为静态的
private static Bank1 instance = new Bank1();
//3.提供公共的静态的方法,返回类的对象
public static Bank1 getInstance() {
return instance;
}
}
2.懒汉式(线程不安全)
- 私有化类的构造器
- 声明当前类对象,没有初始化
- 此对象也必须声明为static的
- 声明public、static的返回当前类对象的方法
public class SingletonTest2 {
public static void main(String[] args) {
Bank2 bank1 = Bank2.getInstance();
Bank2 bank2 = Bank2.getInstance();
System.out.println(bank1 == bank2);
}
}
//懒汉式
class Bank2 {
//1.私有化类的构造器
private Bank2() {
}
//2.声明当前类对象,没有初始化
//4.此对象也必须声明为static的
private static Bank2 instance = null;
//3.声明public、static的返回当前类对象的方法
public static Bank2 getInstance() {
if (instance == null) {
//①
instance = new Bank2();
}
return instance;
}
}
未加锁,在多线程中,第一个线程进入,判断instance为空,进入if在①处,恰好时间片用完了,他不能继续执行了,等待其他线程执行,他也并没有获得锁,没有锁住任何东西,这时第二个线程进来了,这时instance还是空的,也进入了①的位置,时间片也用完了,这时第一个线程执行,第一个线程从①处动身,直接创建一个对象,返回了对象,第二个线程也判断完了从①开始,创建了一个新对象,返回。这样两个线程拿到的对象就不是同一个对象,违背了单例设计模式的原则。
3.懒汉式(线程安全)
public class BankTest {
public static void main(String[] args) {
}
}
class Bank {
private Bank() {
}
private static Bank bank;
public static Bank getBank() {
//方式一:效率稍差(不管有没有给bank实例化上对象,进来的线程都需要等待)
// synchronized (Bank.class) {
// if(bank == null) {
// bank = new Bank();
// }
// return bank;
// }
//方式二(双重检查锁模式):效率更高
if(bank == null) {
synchronized (Bank.class) {
if(bank == null) {
bank = new Bank();
}
}
}
return bank;
}
}
如果是单一线程,推荐使用饿汉模式和懒汉模式(线程不安全的),如果是多线程,并发抢占很激烈的情况,推荐使用双重检查锁模式
二、代理模式(proxy)
要求:
- 必须要有代理类(proxy)和被代理类(target)
- 代理类和被代理类必须是同一个接口或者抽象类、类的子类,一般都是接口
- 在代理类里创建一个目标对象target,并且构造方法初始化它
- 在代理类中重写接口的方法,调用被代理类的执行的方法(真正执行工作的是被代理类)
public interface ITPInterface {
void foo();
}
public class Proxy implements ITPInterface {
private ITPInterface target;
public Proxy(ITPInterface target) {
this.target = target;
}
@Override
public void foo() {
target.foo();
}
}
public class Main {
public static void main(String[] args) {
ITPInterface itpInterface = new Proxy(new Target());
itpInterface.foo();
}
}
可以通过代理模式解开类与类的耦合,让代码执行起来受控程度更加在我们身上,写业务的程序员更加专注于业务。
public class Proxy implements ITPInterface {
private ITPInterface target;
public Proxy(ITPInterface target) {
this.target = target;
}
@Override
public void foo(int a, int b) {//如果b为0就会抛异常,把这个过程放到这里解决
if(b == 0) {
System.out.println("除数不能为0");
}
target.foo(a,b);
System.out.println("执行完成");
}
}
public class Target implements ITPInterface{
@Override
public void foo(int a, int b) {
System.out.println("a/b="+a/b);
}
}
三、工厂模式(factory)
工厂能生产的产品一定是与他原有生产的相似的产品,比如塑料厂,让他生产塑料玩具,但是不能炼钢。工厂能生产东西一定是有一个生产模板
- 确定一个生产模板(接口),所有产品类实现这个接口
- 在工厂类中生产这些产品
public interface IUsb {
void writeData(byte[] bytes);
}
public class Mouse implements IUsb {
@Override
public void writeData(byte[] bytes) {
System.out.println("我是鼠标");
}
}
public class Flash implements IUsb {
@Override
public void writeData(byte[] bytes) {
System.out.println("我是U盘");
}
}
public class Factory {
public static IUsb factory(String args) {
switch (args) {
case "mouse":
return new Mouse();
case "flash":
return new Flash();
default:
return null;
}
}
}
工厂模式最主要的就是要有模板。比如上面的这个工厂就生产usb的东西,只要你要生产跟usb有关的东西(实现IUsb接口)就可以往这个工厂的流水线里放。然后你要主类中生产这个产品时根本不用new,new的过程放在了工厂里。
四、建造者模式(builder)
- 创建一个类Target,类里的属性和构造方法都是私有的,且没有set/get方法,其他方法都是公开的,所有的建造过程放在建造者里完成(这个类是建造的目标物)
- 创建一个建造类TargetBuilder(所有的建造过程写在这个类),Target类有什么属性,这个类就要有什么属性
建造者模式能最大程度上保护Target对象的内部的所有的内容,如果碰到一个类不能直接new他的对象,就可以用这个模式
静态建造者模式:
public class TTarget {
private int length;
private String color;
private TTarget() {
}
public void foo() {
System.out.println(color + "," +length);
}
}
public class TTargetBuilder {
private static TTargetBuilder tTargetBuilder = new TTargetBuilder();
private static int length;
private static String color;
private TTargetBuilder() {
}
public TTarget build () {
Class c = TTarget.class;
try {
Constructor declaredConstructor = c.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
Field length = c.getDeclaredField("length");
length.setAccessible(true);
length.set(o,this.length);
Field color = c.getDeclaredField("color");
color.setAccessible(true);
color.set(o,this.color);
return (TTarget) o;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
public static TTargetBuilder setLength(int length) {
//this.length = length;//静态方法里不能用this
tTargetBuilder.length = length;
return tTargetBuilder;
}
public static TTargetBuilder setColor(String color) {
tTargetBuilder.color = color;
return tTargetBuilder;
}
}
动态建造者模式:
public class TTarget {
private int length;
private String color;
private TTarget() {
}
public void foo() {
System.out.println(color + "," +length);
}
}
public class TTargetBuilder {
private int length;
private String color;
public TTargetBuilder() {
}
public TTarget build () {
Class c = TTarget.class;
try {
Constructor declaredConstructor = c.getDeclaredConstructor();
declaredConstructor.setAccessible(true);
Object o = declaredConstructor.newInstance();
Field length = c.getDeclaredField("length");
length.setAccessible(true);
length.set(o,this.length);
Field color = c.getDeclaredField("color");
color.setAccessible(true);
color.set(o,this.color);
return (TTarget) o;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
return null;
}
public TTargetBuilder setLength(int length) {
this.length = length;
return this;
}
public static TTargetBuilder setColor(String color) {
this.color = color;
return this;
}
}
public class Main {
public static void main(String[] args) {
TTarget tTarget = new TTargetBuilder().setColor("黄色").setLength(1000).build();//只有调用build方法才创建对象,可以极大的降低,创建对象耗费的资源
tTarget.foo();
}
}