- content {:toc}
1、单例
//饿汉模式,很饿很着急,所以类加载时即创建实例对象
public class Singleton1 {
private static Singleton1 singleton = new Singleton1();
private Singleton1() {
}
public static Singleton1 getInstance() {
return singleton;
}
}
//饱汉模式(懒汉),很饱不着急,延迟加载,啥时候用啥时候创建实例,存在线程安全问题
public class Singleton2 {
private static Singleton2 singleton;
private Singleton2() {
}
public static synchronized Singleton2 getInstance() {
if (singleton == null)
singleton = new Singleton2();
return singleton;
}
}
//饱汉模式的双重锁模式,提高效率
public class Singleton3 {
//使用volatile 关键字修饰,防止指令重排
//若发生指令重排,可能出现new Singleton3();时还没初始化完成(仅仅分配内存)就赋值给singleton
//这时有另外的线程获取对象就是未初始化完的
private static volatile Singleton3 singleton;
private Singleton3() {
}
public static Singleton3 getInstance() {
if (singleton == null) {
synchronized (Singleton3.class) {
if (singleton == null) {
singleton = new Singleton3();
}
}
}
return singleton;
}
}
//如果单例需要延迟加载,又要线程安全且代码简洁
//使用内部类实现,在加载Singleton4时是不会加载InnerCls的,也就不会走new Singleton4()
// 只有调用getInstance()时用到了InnerCls才会被加载
public class Singleton4 {
private Singleton4() {
}
public static Singleton4 getInstance() {
return InnerCls.singleton;
}
private static class Inner {
private static final Singleton4 singleton = new Singleton4();
}
}
2、工厂
要生成如下产品:
//抽象产品
public abstract class Product {
}
//具体产品A
public class ProductA extends Product {
}
//具体产品B
public class ProductB extends Product {
}
简单工厂模式
- type方式传入,不符合开闭原则,新增要修改代码
public class SimpleCreator {
public static <T extends Product> T createProduct(int type) {
switch (type) {
case 1:
return new ProductA();
break;
case 2:
return new ProductB();
break;
}
return null;
}
}
- 使用反射 缺点:
- Class.forName(clz.getName()).newInstance()调用的是无参构造函数生成对象,它和new Object()是一样的性质,而工厂方法应该用于复杂对象的初始化 ,当需要调用有参的构造函数时便无能为力了,这样像为了工厂而工厂。
- 不同的产品需要不同额外参数的时候 不支持。
public class SimpleCreator {
public static <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
}
return (T) product;
}
}
- 多方法创建 有地方叫多方法工厂,java.util.concurrent.Executors使用
优点方便创建 同种类型的 复杂参数的对象
缺点 不符合开闭
public class SimpleCreator {
public static <T extends Product> T createProductA() {
return new ProductA();
}
public static <T extends Product> T createProductB() {
return new ProductB();
}
}
工厂方法模式
普通工厂就是把简单工厂中具体的工厂类,划分成两层:抽象工厂层+具体的工厂子类层。(一般->特殊)
//抽象工厂类
public abstract class Creator {
public abstract <T extends Product> T createProduct(Class<T> c);
}
//具体工厂类
public class ProductCreator extends Creator {
@Override
public <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
}
return (T) product;
}
}
//或不使用反射,根据字符串内部判断生成的类,为每个产品创建一个工厂,也能达到开闭原则,但是类会变多
public abstract class Creator {
public Product createProduct();
}
//具体工厂类
public class ProductACreator extends Creator {
@Override
public Product createProduct() {
return new ProductA();
}
}
public class ProductBCreator extends Creator {
@Override
public Product createProduct() {
return new ProductB();
}
}
抽象工厂模式
abstract class Product 是一个产品大类(产品族),如果要在一个工厂中创建两个产品族(因为两个产品族有关系,如一辆车的左右门数量要一致),则需要使用抽象工厂模式
//另一个抽象产品族(礼物)
public abstract class Gift {
}
//礼物A
public class GiftA extends Gift {
}
//礼物B
public class GiftB extends Gift {
}
//抽象工厂类
public abstract class AbstractCreator {
public abstract <T extends Product> T createProduct(Class<T> c);
public abstract <T extends Gift> T createGift(Class<T> c);
//若有多个产品族,则需要多个方法,违反开闭原则
}
//具体工厂类
public class ProductGiftCreator extends AbstractCreator {
@Override
public <T extends Product> T createProduct(Class<T> c) {
Product product = null;
try {
product = (Product) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
}
return (T) product;
}
@Override
public <T extends Gift> T createGift(Class<T> c) {
Gift gift = null;
try {
gift = (Gift) Class.forName(c.getName()).newInstance();
} catch (Exception e) {
}
return (T) gift;
}
}
建造者模式
构造方法参数多,而且参数需要进一步处理
常用lombok 的@Builder 即可对一个实体类构建出建造者