关注公众号获取更多资料
设计模式–建造者模式
创建型模式包含单例模式,原型模式,工厂方法模式,抽象工厂模式,建造者模式。主要是用来获取或生成一个对象供程序使用。
单例模式
单例模式是指在整个程序中只生成一个实例供所有功能使用,我们并不能自己去创建一个实例对象,所以在定义的时候需要将所有的构造方法都设为私有。根据实例对象的创建时期还可以分为饿汉模式和懒汉模式。
饿汉模式
饿汉模式假定当前实例对象一定会被使用,所以在程序加载的时候就被创建出来。
class HungrySinglaton {
private
HungrySinglaton instance = new HungrySinglaton();
private HungrySinglaton() {}
public static HungrySinglaton getInstance() {
return instance;
}
}
懒汉模式并不需要考虑线程安全,因为在在加载当前类的时候就已经将对象创建出来了,所以不会存在多份。构造方法私有化避免了私自new。
获取多次实例并打印,查看是否是同一个对象:
Arrays.stream(new int[]{1, 2, 3, 4}).forEach(i ->
new Thread(() ->
System.out.println(HungrySinglaton.getInstance())
).start()
);
注意:此处不能使用Arrays.asList(new int[]{1,2,3,4}),否则循环的时候只会循环一次,并且循环的元素是数组。另外lambada表达式在只有一句逻辑的时候是可以省略"{}“的,并且执行语句之后不需要添加”;"。
执行结果如下:
com.wupengchoy.mystudy.designpattern.creater.HungrySinglaton@2fa7eff5
com.wupengchoy.mystudy.designpattern.creater.HungrySinglaton@2fa7eff5
com.wupengchoy.mystudy.designpattern.creater.HungrySinglaton@2fa7eff5
com.wupengchoy.mystudy.designpattern.creater.HungrySinglaton@2fa7eff5
说明每次获取的都是同一个对象。
懒汉模式
懒汉模式假定实例对象在程序中可能不会被使用,只有在需要的时候才会被创建出来。此时可能同时又多个线程调用创建对象的逻辑,需要考虑并发。
class LazySinglaton {
private static LazySinglaton instance;
private LazySinglaton() {}
public static LazySinglaton getInstance() {
if (instance == null) {
synchronized (LazySinglaton.class) {
if (instance == null) {
instance = new LazySinglaton();
}
}
}
return instance;
}
}
为什么同步的时候直接将Synchronized添加在方法上,原因是如果并发量大,每次都会同步,这样导致代码效率很低,上面的用法只在为空的时候才会同步,速度会快很多。
测试代码:
Arrays.stream(new int[]{1, 2, 3, 4}).forEach(i -> new Thread(() ->
System.out.println(LazySinglaton.getInstance())
).start());
输出结果如下:
com.wupengchoy.mystudy.designpattern.creater.LazySinglaton@630e6938
com.wupengchoy.mystudy.designpattern.creater.LazySinglaton@630e6938
com.wupengchoy.mystudy.designpattern.creater.LazySinglaton@630e6938
com.wupengchoy.mystudy.designpattern.creater.LazySinglaton@630e6938
扩展-多例模式
有的情况下可能当前实例不是单例,但是也不允许无限制的创建,此时需要创建一个定长的数组,储存指定个数的实例对象。
class MultiSinglaton {
private static int MAX_LENGTH = 4;
private static List<MultiSinglaton> instances = new ArrayList<>(MAX_LENGTH);
private MultiSinglaton() {}
public static MultiSinglaton getInstance() {
if (instances.size() == 0) {
for (int i = 1; i <= 4; i++) {
instances.add(new MultiSinglaton());
}
}
return instances.get((int) (Math.random() * MAX_LENGTH));
}
}
在测试的时候创建一个Set集合,循环获取1000次当前实例并添加到集合中,最后查看当前集合的长度,如果超过4,则说明多例模式不能限制创建对象的个数。
Set<MultiSinglaton> singlatons = new HashSet<>();
for (int i = 0; i < 1000; i++) {
singlatons.add(MultiSinglaton.getInstance());
}
System.out.println(singlatons.size());
最终输出结果为4,结果正确。
原型模式
原型模式:用一个已经创建的对象作为原型,通过复制来创建一个与原来相同或类似的对象。通常情况下用来创建比较复杂的对象。
简单原型
Java的Cloneable接口可以实现对象的浅克隆,这里可以简单的通过实现这个接口取进行克隆。
- 创建一个原型接口
interface Pic extends Cloneable {
double area();
Pic getInstance();
}
- 创建具体的对象
这里创建一个圆并计算他的面积:
class Circle implements Pic {
private static Circle cirlce = new Circle();
private int r = 0;
private Circle() {}
public void setR(int r) {this.r = r;}
public static Circle circle() {
try {
return (Circle) cirlce.clone();
} catch (Exception e) {
}
return cirlce;
}
public static Circle circle(int r) {
try {
Circle newCircle = (Circle) cirlce.clone();
newCircle.r = r;
return newCircle;
} catch (Exception e) {
}
return cirlce;
}
@Override
public double area() {
return 3.14 * r * r;
}
@Override
public Pic getInstance() {
return circle();
}
}
与单例模式类似,这里同样不允许自己创建对象,而是通过getInstance或circle方法创建,在方法中使用克隆方式将已有的对象复制,然后返回给调用者。
- 测试
System.out.println(Circle.circle());
//输出:com.wupengchoy.mystudy.designpattern.creater.Circle@255316f2
扩展-添加原型管理器
当有很多个原型需要管理的时候,可以将所有的原型统一起来,使用原型管理器。
原型管理器:
class PrototypeManagement {
private static Map<Class<?>, Pic> map = new HashMap<>();
public static Pic getObject(Class<?> clz) {
try {
if (!map.containsKey(clz)) {
Method instanceMethod = clz.getMethod("circle", new Class[]{});
map.put(clz, (Pic) instanceMethod.invoke(null, new Object[]{}));
}
Pic pic = map.get(clz);
return pic.getInstance();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
原型管理器通过一个map储存了所有需要用到的原型,当需要使用这些原型进行克隆的时候就从map中获取,然后在复制出来。
创建测试:
Circle circle = (Circle) PrototypeManagement.getObject(Circle.class);
circle.setR(2);
System.out.println(circle.area());//输出:12.56
工厂模式
工厂模式将对象的创建和使用相分离,通常包含下面几个部分:抽象工厂,具体工厂,抽象产品,具体产品。根据规格的不同,还可以分为简单工厂模式和抽象工厂模式。简单工厂模式就是只有一家工厂,只有一种产品,这种工厂模式比较简单。如果有多家工厂需要生产多种产品呢。比如工厂A和共产B同时都可以出产产品C和产品D,下面举例说明。
场景:工厂FactoryA和工厂FactoryB都能够出产苹果和奶牛,需要设计如下几步:
- 创建抽象产品
interface Fruit {
void say();
}
interface Animal {
void say();
}
- 创建抽象工厂,因为每个工厂都需要出产苹果和奶牛,所以在接口中创建出产水果和动物的方法,此处用于创建苹果和奶牛的方法每个工厂都是通用的,所以使用默认方法在接口中实现创建产品的逻辑。
interface Factory {
Fruit getFruit(Class<?> clz);
Animal getAnimal(Class<?> clz);
default Object getInstance(Class<?> clz, String factoryName) {
try {
return clz.getConstructor(new Class[]{String.class}).newInstance(new Object[]{factoryName});
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
- 创建具体工厂-在每个工厂中创建对象的方法调用了接口中的default方法
class FactoryA implements Factory {
@Override
public Fruit getFruit(Class<?> clz) {
return (Fruit) getInstance(clz, this.getClass().getSimpleName());
}
@Override
public Animal getAnimal(Class<?> clz) {
return (Animal) getInstance(clz, this.getClass().getSimpleName());
}
}
class FactoryB implements Factory {
@Override
public Fruit getFruit(Class<?> clz) {
return (Fruit) getInstance(clz, this.getClass().getSimpleName());
}
@Override
public Animal getAnimal(Class<?> clz) {
return (Animal) getInstance(clz, this.getClass().getSimpleName());
}
}
- 创建具体产品
class Apple implements Fruit {
private String source;
public Apple(String source) {
this.source = source;
}
@Override
public void say() {
System.out.println("i am apple " + (StringUtils.isNotBlank(this.source) ? "from " + source : ""));
}
}
class Cow implements Animal {
private String source;
public Cow(String source) {
this.source = source;
}
@Override
public void say() {
System.out.println("i am cow " + (StringUtils.isNotBlank(this.source) ? "from " + source : ""));
}
}
- 测试:
Factory factoryB = new FactoryB();
factoryB.getAnimal(Cow.class).say();//i am cow from FactoryB
factoryB.getFruit(Apple.class).say();//i am apple from FactoryB
Factory factoryA = new FactoryA();
factoryA.getAnimal(Cow.class).say();//i am cow from FactoryA
factoryA.getFruit(Apple.class).say();//i am apple from FactoryA
建造者模式
建造者通常用于创建比较复杂的对象,由多个部件组成,每个部件的创建分离,然后组装成最终的对象。除此之外,每个部件可以灵活更换。建造者模式通常由以下结构组成:
- 产品角色(Product):由多个Part组成。
- 抽象建造者(Builder):能够创建Part的接口。
- 具体建造者:实现了抽象建造者。
- 指挥者(Director):管理调用多个建造者,并指挥生产部件组装成产品。
- 创建产品角色以及其包含的各个部件
interface Part {}
class PartA implements Part {
String name = "partA";
}
class PartB implements Part {
String name = "partB";
}
class Product {
private PartA partA;
private PartB partB;
public void setPartA(PartA partA) {
this.partA = partA;
}
public PartA getPartA() {
return partA;
}
public void setPartB(PartB partB) {
this.partB = partB;
}
public PartB getPartB() {
return partB;
}
}
- 创建抽象建造者和具体建造者-每个建造者创建不同的Part
interface MyBuilder {
Part buildPart();
}
class BuilerA implements MyBuilder {
public BuilerA() {}
@Override
public PartA buildPart() {
return new PartA();
}
}
class BuilerB implements MyBuilder {
public BuilerB() {}
@Override
public PartB buildPart() {
return new PartB();
}
}
- 创建指挥者
class Director {
private List<MyBuilder> builers = new ArrayList<>();
//根据不停的Class创建实例
public void creatBuilder(Class<?> clz) {
try {
this.builers.add((MyBuilder) clz.getConstructor(new Class[]{}).newInstance(new Object[]{}));
} catch (Exception e) {
e.printStackTrace();
}
}
//初始化的时候创建每个建造者
public Director(List<Class<?>> clzs) {
clzs.forEach(this::creatBuilder);
}
//根据不同的建造者创建Part并组装成产品
public Product getProduct() {
Product product = new Product();
builers.forEach(builder -> {
if (builder instanceof BuilerA) {
product.setPartA(((BuilerA) builder).buildPart());
} else {
product.setPartB(((BuilerB) builder).buildPart());
}
});
return product;
}
}
- 测试
List<Class<?>> clzs = new ArrayList<>();
clzs.add(BuilerA.class);
clzs.add(BuilerB.class);
Director director = new Director(clzs);
Product product = director.getProduct();
System.out.println(product.getPartA().name + ":" + product.getPartB().name);
//输出:partA:partB
最后测试发现能够正常组装产品,并且组装完成的产品包含了各个部件。