设计模式——创建型模式简单介绍

创建型模式

创建型模式的作用就是创建对象,说到创建一个对象,最熟悉的就是 new 一个对象,然后 set 相关属性。但是,在很多场景下,我们需要给客户端提供更加友好的创建对象的方式,尤其是那种我们定义了类,但是需要提供给其他开发者用的时候。

简单工厂模式

简单工厂模式通常就是一个工厂类 XxxFactory,里面有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。

工厂模式

引入工厂模式,是因为我们往往需要使用两个或两个以上的工厂。

XxxFactory工厂接口A,有个方法。XxxFactory工厂类A1,XxxFactory工厂类A2实现了那个接口里的方法。每个模式中和简单工厂模式一样。

工厂模式

抽象工厂模式

当涉及到产品族的时候,就需要引入抽象工厂模式了。

违反了对修改关闭,对扩展开放这个设计原则。

abstract-factory-3

单例模式——1个类只有一个实例

枚举,枚举很特殊,它在类加载的时候会初始化里面的所有的实例,而且 JVM 保证了它们不会再被实例化,所以它天生就是单例的。

虽然我们平时很少看到用枚举来实现单例,但是在 RxJava 的源码中,有很多地方都用了枚举来实现单例。

饿汉模式:

  • private构造方法(防止被实例化)
  • 先实例一个static的,private static SingleObject instance = new SingleObject();
  • 一个static获得该对象的方法,直接return

懒汉式/饱汉模式 的优化双重检测:

  • private构造方法(防止被实例化)
  • 先不实例出来,但要volatile,private static volatile Singleton instance = null;
  • 一个static获得该对象的方法,非null直接return,null就加锁 synchronized在类上 再实例化。
	public static Singleton getInstance() {
        if (instance == null) {
            // 加锁
            synchronized (Singleton.class) {
                // 这一次判断也是必须的,不然会有并发问题
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
// 双重检查:instance为null

嵌套类:嵌套类最经典,强烈推荐★★★

  • private构造方法(防止被实例化)
  • 实例化在嵌套类
  • 一个static获得该对象的方法,调用嵌套类的那个实例
public class Singleton3 {

    private Singleton3() {}
    // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
    // 实例化的部分在嵌套类中
    private static class Holder {
        private static Singleton3 instance = new Singleton3();
    }
    public static Singleton3 getInstance() {
        return Holder.instance;
    }
}

枚举类:所有单例实现唯一不会被破坏的

枚举类实现单例模式相当硬核,因为枚举类型是线程安全的,且只会装载一次。使用枚举类来实现单例模式,是所有的单例实现中唯一一种不会被破坏的单例模式实现。

  • private构造方法(防止被实例化)
  • 枚举类中:
    • final对象,private构造方法实例化
    • 获取枚举对象
  • 一个static获得该对象的方法,调用枚举类的那个实例
public class SingletonObject {

    private SingletonObject() {
    }
	// 内部创建枚举类:枚举类型是线程安全的且只会装载一次
    private enum Singleton {
        INSTANCE;
        private final SingletonObject instance;
        Singleton() {
            instance = new SingletonObject();
        }
        private SingletonObject getInstance() {
            return instance;
        }
    }

    public static SingletonObject getInstance() {
        return Singleton.INSTANCE.getInstance();
    }
}

建造者模式

XxxBuilder ,对于客户端来说,我们的使用通常都是一个模式的:

  • 先 new 一个 Builder
  • 然后可以链式地调用一堆方法:怎样链式调用?只要那些方法返回那个类就行。
  • 最后再调用一次 build() 方法,我们需要的对象就有了
// 1.先 new 一个 Builder
// 2.然后可以链式地调用一堆方法:怎样链式调用?只要那些方法返回那个类就行。
// 3.最后再调用一次 build() 方法,我们需要的对象就有了

Food food = new FoodBuilder().a().b().c().build();
Food food = Food.builder().a().b().c().build();

中规中矩的建造者模式示例:

核心是:先把所有的属性都设置给 Builder,然后 build() 方法的时候,将这些属性复制给实际产生的对象。

User类

  • 有一堆属性和私有构造方法
  • 返回一个static的 UserBuilder对象:new Builder
  • public build()方法:将 UserBuilder 中设置好的属性“复制”到 User 中,new出一个User对象,return。(最后一步)

UserBuilder在User类中

  • 有一堆属性和私有构造方法
  • 链式调用设置各个属性值,返回 this,即 UserBuilder
class User {
    // 下面是“一堆”的属性
    private String name;
    private String password;
    private String nickName;
    private int age;

    // 构造方法私有化,不然客户端就会直接调用构造方法了
    private User(String name, String password, String nickName, int age) {
        this.name = name;
        this.password = password;
        this.nickName = nickName;
        this.age = age;
    }
    // 静态方法,用于生成一个 Builder,这个不一定要有,不过写这个方法是一个很好的习惯,
    // 有些代码要求别人写 new User.UserBuilder().a()...build() 看上去就没那么好
    public static UserBuilder builder() {
        return new UserBuilder();
    }

    public static class UserBuilder {
        // 下面是和 User 一模一样的一堆属性
        private String  name;
        private String password;
        private String nickName;
        private int age;

        private UserBuilder() {
        }

        // 链式调用设置各个属性值,返回 this,即 UserBuilder
        public UserBuilder name(String name) {
            this.name = name;
            return this;
        }

        public UserBuilder password(String password) {
            this.password = password;
            return this;
        }

        public UserBuilder nickName(String nickName) {
            this.nickName = nickName;
            return this;
        }

        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }

        // build() 方法负责将 UserBuilder 中设置好的属性“复制”到 User 中。
        // 当然,可以在 “复制” 之前做点检验
        public User build() {
            if (name == null || password == null) {
                throw new RuntimeException("用户名和密码必填");
            }
            if (age <= 0 || age >= 150) {
                throw new RuntimeException("年龄不合法");
            }
            // 还可以做赋予”默认值“的功能
              if (nickName == null) {
                nickName = name;
            }
            return new User(name, password, nickName, age);
        }
    }
}

当属性很多,而且有些必填,有些选填的时候,这个模式会使代码清晰很多。我们可以在 Builder 的构造方法中强制让调用者提供必填字段,还有,在 build() 方法中校验各个参数比在 User 的构造方法中校验,代码要优雅一些。

使用 lombok:@Builder

强烈建议读者使用 lombok,用了 lombok 以后,上面的一大堆代码会变成如下这样:

@Builder
class User {
    private String  name;
    private String password;
    private String nickName;
    private int age;
}

当然,如果你只是想要链式写法,不想要建造者模式,有个很简单的办法,User 的 getter 方法不变,所有的 setter 方法都让其 return this 就可以了,然后就可以像下面这样调用:

User user = new User().setName("").setPassword("").setAge(20);

原型模式

在原型实例的基础上产生新的实例。

Object 类中有一个 clone() 方法,它用于生成一个新的对象,当然,如果我们要调用这个方法,java 要求我们的类必须先实现 Cloneable 接口,此接口没有定义任何方法,但是不这么做的话,在 clone() 的时候,会抛出 CloneNotSupportedException 异常。

protected native Object clone() throws CloneNotSupportedException;

java 的克隆是浅克隆,碰到对象引用的时候,克隆出来的对象和原对象中的引用将指向同一个对象。通常实现深克隆的方法是将对象进行序列化,然后再进行反序列化。

原型模式了解到这里我觉得就够了,各种变着法子说这种代码或那种代码是原型模式,没什么意义。

创建型模式总结

作用:创建实例对象

简单工厂模式最简单;工厂模式在简单工厂模式的基础上增加了选择工厂的维度,需要第一步选择合适的工厂;抽象工厂模式有产品族的概念,如果各个产品是存在兼容性问题的,就要用抽象工厂模式

单例模式,为了保证全局使用的是同一对象,一方面是安全性考虑,一方面是为了节省资源;

建造者模式专门对付属性很多的那种类,为了让代码更优美;

原型模式用得最少,了解和 Object 类中的 clone() 方法相关的知识即可。

引用:设计模式也可以这么简单

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值