聊一聊设计模式(二)-- 建立型设计模式

前言

昨天讲了六大原则,今天就进入设计模式的正题了。java

思惟导图

建立型设计模式,顾名思义就是与对象的建立相关。设计模式

单例模式

定义:保证一个类仅有一个实例,并提供用于一个访问它的全局访问点。安全

5种写法及其优缺点

(1) 饿汉模式ide

public class Singleton {
    private static Singleton instance = new Singleton();
    
    public static Singleton getInstance(){
        return instance;
    }
}
复制代码

在类加载时就已经完成了初始化。 优势:1. 保障了线程同步的问题;2. 获取对象的效率高。 缺点:1. 下降了类加载时速度;2. 若是一直不使用,会内存的浪费。函数

(2) 懒汉模式学习

  1. 线程不安全
public class Singleton {
    private static Singleton instance;
    
    public static Singleton getInstance(){
        if(instance == null) instance = new Singleton();
        return instance;
    }
}
复制代码

缺点:存在线程同步问题 2. 线程安全ui

public class Singleton {
    private static Singleton instance;
    
    public static synchronized Singleton getInstance(){
        if(instance == null) instance = new Singleton();
        return instance;
    }
}
复制代码

缺点:每一次都须要同步,存在必定的开销问题。this

懒汉模式相较于饿汉模式,不会存在不使用的问题。虽然再也不在加载时消耗资源,可是实例化时一样会有必定的时间开销。 (3) 双重检查模式/DCLspa

public class Singleton {
    private volatile static Singleton instance;

    public static Singleton getInstance(){
        if(instance == null) {
            synchronized (Singleton.class){
                if(instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}
复制代码

使用volatile关键词是对正确性的一种保障。 相较于懒汉模式而言,这又是一种升级。由于不在将synchronized套在了函数上,也就不会每次调用都对整个函数同步了,提升了资源的利用率。可是一样存在失效的状况。线程

失效案例

(4) 静态内部类单例模式

public class Singleton {

    public static Singleton getInstance() {
        return SingletonHolder.instance;
    }

    private static class SingletonHolder {
        private volatile static Singleton instance = new Singleton();
    }
}
复制代码

这是最经常使用的方法,也是对DCL的一种升级。 优缺点和前面都差很少,就再也不复述了。 (5) 枚举单例模式

public enum  Singleton {
    INSTANCE;  
}
复制代码

这是一种通常不经常使用的方法,可是可以保障线程同步。

简单工厂模式

定义:又称静态工厂模式,是由一个工厂对象决定建立出那一种产品类的实例。

既然是一个工厂就举一个工厂的例子。 通常来讲的工厂模式都是这样的: 客户 --> 工厂 --> 产品 因此产生了三个类

/** * 工厂类 */
public class Factory {
    public static Product product(String type){
        Product product = null;
        switch (type){
            case "鸡翅":
                product = new ChickenWing();
                break;
            case "汉堡":
                product = new Hamburger();
                break;
        }
        return product;
    }
}

/** * 抽象产品类 */
public abstract class Product {
    public abstract void finish();
}

/** * 具体产品类 */
public class Hamburger extends Product {
    @Override
    public void finish() {
        System.out.println("汉堡制做完成");
    }
}

public class ChickenWing extends Product {
    @Override
    public void finish() {
        System.out.println("鸡翅制做完成");
    }
}
复制代码

三个类已经完成了对应,就跟你在肯德基吃饭同样,告诉他一个名字,他就开始生产。

优势:根据参数得到实例,下降了耦合度。 缺点:不利于扩展功能,由于工厂从一开始就知道能加载的有什么。 使用场景:(1) 工厂负责建立的对象较少;(2)客户只须要知道想要什么,不用关心怎么生成的时候。

工厂方法模式

定义:定义一个用于建立对象的接口,让子类决定实例化哪一个类。工厂方法将类的实例化放到子类中实现。

工厂模式中的四个角色:

  1. Product:产品抽象类
  2. Factory:工厂抽象类,返回Product对象
  3. ConcreteProduct:具体产品类
  4. ConcreteFactory:具体工厂类 其实就是对简单工厂方法的一种升级,由于在简单工厂方法中,只有产品这一层被抽象出来了。而工厂方法是把工厂也抽象出来。 因此如下代码是对简单工厂方法的一种改进。
/** * 抽象工厂类 */
public abstract class Factory {
    public abstract <T extends Product> T product(Class<T> clazz);
}

/** * 具体工厂类 */
public class KFC extends Factory {
    @Override
    public <T extends Product> T product(Class<T> clazz) {
        Product product = null;
        try{
            product = (Product) Class.forName(clazz.getName()).newInstance();
        }catch (Exception e){
            e.printStackTrace();
        }
        return (T) product;
    }
}
复制代码

使用反射机制,也就解决了简单工厂中分支可能存在增长的问题了。

建造者模式

讲一个复杂对象的构建与它的表示分离,使一样的构建过程能够建立不一样的表示。

四个角色:

  1. Director:导演类,将工做按顺序完成。
  2. Builder:生成抽象类,生产产品的模版,具体操做由子类完成。
  3. ConcreteBuilder:生成具体类。
  4. Product:产品类。 跟简单工厂不同,这一次的主角变成了肯德基里服务的店员们了,他们负责完成汉堡制做的各项流程,而Builder只是说明要干什么事情。
/** * 导演类 */
public class Director {
    Builder builder;
    
    Director(Builder builder){
        this.builder = builder;
    }
    
    public Hamburger create(String meat, String vegetable, String bread){
        builder.cookBread(bread);
        builder.cookMeat(meat);
        builder.cookVegetable(vegetable);
        return builder.finish();
    }
}

/** * Builder抽象类 */
public abstract class Builder {
    public abstract void cookMeat(String meat);
    public abstract void cookBread(String bread);
    public abstract void cookVegetable(String vegetable);
    public abstract Hamburger finish();
}

/** * Builder类 */
public class ChickenHamburgerBuilder extends Builder{

    private Hamburger hamburger = new Hamburger();

    @Override
    public void cookMeat(String meat) {
        hamburger.setMeat(meat);
    }

    @Override
    public void cookBread(String bread) {
        hamburger.setBread(bread);
    }

    @Override
    public void cookVegetable(String vegetable) {
        hamburger.setVegetable(vegetable);
    }

    @Override
    public Hamburger finish() {
        return hamburger;
    }
}

/** * 产品类 */
public class Hamburger {
    private String vegetable;
    private String meat;
    private String bread;

    // 如下省略Getter 和 Setter方法
}
复制代码

以上就是个人学习成果,若是有什么我没有思考到的地方或是文章内存在错误,欢迎与我分享。


相关文章推荐:

聊一聊设计模式(一)-- 六大原则

聊一聊设计模式(三)-- 结构型设计模式

聊一聊设计模式(四)-- 行为型设计模式

相关文章
相关标签/搜索