设计模式其实很简单之建造者模式

关注公众号获取更多资料
在这里插入图片描述

设计模式–建造者模式

​ 创建型模式包含单例模式,原型模式,工厂方法模式,抽象工厂模式,建造者模式。主要是用来获取或生成一个对象供程序使用。

单例模式

​ 单例模式是指在整个程序中只生成一个实例供所有功能使用,我们并不能自己去创建一个实例对象,所以在定义的时候需要将所有的构造方法都设为私有。根据实例对象的创建时期还可以分为饿汉模式懒汉模式

饿汉模式

​ 饿汉模式假定当前实例对象一定会被使用,所以在程序加载的时候就被创建出来。

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

​ 最后测试发现能够正常组装产品,并且组装完成的产品包含了各个部件。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值