设计模式之创建者模式

184 阅读5分钟

创建型模式总体上比较简单,它们的作用就是为了产生实例对象,算是各种工作的第一步了,因为我们写的是面向对象的代码,所以我们第一步当然是需要创建一个对象了。

简单工厂模式最简单;工厂模式在简单工厂模式的基础上增加了选择工厂的维度,需要第一步选择合适的工厂;抽象工厂模式有产品族的概念,如果各个产品是存在兼容性问题的,就要用抽象工厂模式。单例模式就不说了,为了保证全局使用的是同一对象,一方面是安全性考虑,一方面是为了节省资源;建造者模式专门对付属性很多的那种类,为了让代码更优美;原型模式用得最少,了解和 Object 类中的 clone() 方法相关的知识即可。

1.工厂模式

它提供了一种创建对象的最佳方式

public interface Skewer {
    public String create();
}
public class PorkSkewer implements Skewer {
    @Override
    public String create() {
        return "我烤的是猪肉串...";
    }
}
public class MuttonSkewer implements Skewer {
    @Override
    public String create() {
        return "我烤得是羊肉串...";
    }
}
public class SkewerFactory {
    public static Skewer getSkewer(String param){
        if (param.equals("mutton")){
            return new MuttonSkewer();
        }else if (param.equals("pork")){
            return new PorkSkewer();
        }else {
            return null;
        }
    }

    public static void main(String[] args) {
        Skewer mutton = SkewerFactory.getSkewer("mutton");
        System.out.println(mutton.create());//我烤得是羊肉串...
        System.out.println("*************");
        Skewer pork = SkewerFactory.getSkewer("pork");
        System.out.println(pork.create());//我烤的是猪肉串...
    }
}

2.抽象工厂模式

是围绕一个超级工厂创建其他工厂,当涉及到产品族的时候,就需要引入抽象工厂模式了

/** 搞烧烤 */
public interface Skewer {
    public String create();
}
public class MuttonSkewer implements Skewer {
    @Override
    public String create() {
        return "羊肉串准备起来";
    }
}
public class PorkSkewer implements Skewer {
    @Override
    public String create() {
        return "猪肉串准备起来";
    }
}

/** 搞些啤酒恰 */
public interface Beer {
    public String create();
}

public class QingDaoBeer implements Beer {
    @Override
    public String create() {
        return "青岛啤酒来了";
    }
}

public class HuangheBeer implements Beer {
    @Override
    public String create() {
        return "黄河啤酒来了";
    }
}

/** 创建一个工厂,通过传递啤酒或者烧烤的信息获取工厂 */
public abstract class AbstractFactory {
    abstract Skewer getSkewer(String skewerName);
    abstract Beer getBeer(String beerName);
}

/** 啤酒工厂 */
public class BeerFactory extends AbstractFactory{
    @Override
    Skewer getSkewer(String skewerName) {
        return null;
    }

    @Override
    Beer getBeer(String beerName) {
        if (beerName.equals("qingdao")){
            return new QingDaoBeer();
        }else if (beerName.equals("huanghe")){
            return new HuangheBeer();
        }else {
            return null;
        }
    }
}

/** 烧烤工厂 */
public class SkewerFactory extends AbstractFactory {
    @Override
    Skewer getSkewer(String skewerName) {
        if (StringUtils.isEmpty(skewerName)){
            return null;
        }else if (skewerName.equals("mutton")){
            return new MuttonSkewer();
        }else if (skewerName.equals("pork")){
            return new PorkSkewer();
        }
        return null;
    }

    @Override
    Beer getBeer(String beerName) {
        return null;
    }
}

/** 老板上菜 */
public class FactoryProduct {
    public static AbstractFactory getFactory(String name){
        if (name.equals("skewer")){
            return new SkewerFactory();
        }else if (name.equals("beer")){
            return new BeerFactory();
        }
        return null;
    }

    public static void main(String[] args) {
        AbstractFactory skewer = FactoryProduct.getFactory("skewer");
        Skewer mutton = skewer.getSkewer("mutton");
        System.out.println(mutton.create());
        System.out.println("*************");
        AbstractFactory beer = FactoryProduct.getFactory("beer");
        Beer huanghe = beer.getBeer("qingdao");
        System.out.println(huanghe.create());
    }
}

3.建造者模式

使用多个简单的对象一步一步构建成一个复杂的对象

优点:

  1. 使用建造者模式可以使客户端不必知道产品内部组成的细节。

  2. 具体的建造者类之间是相互独立的,这有利于系统的扩展。

  3. 具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。

缺点:

  1. 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似;如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。

  2. 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大。

public class BarbecueCake {
    private String name;
    private double price;

    @Override
    public String toString() {
        return "BarbecueCake{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }

    // 不容许客户度直接调用构造方法
    private BarbecueCake(){}

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public static BarbecueCakeBuilder builder(){
        return new BarbecueCakeBuilder();
    }

    public static class BarbecueCakeBuilder{
        private String name;
        private double price;

        private BarbecueCakeBuilder(){}

        public BarbecueCakeBuilder name(String name){
            this.name=name;
            return this;
        }
        public BarbecueCakeBuilder price(double price){
            this.price=price;
            return this;
        }
        public BarbecueCake build(){
            BarbecueCake bc = new BarbecueCake();
            bc.setName(this.name);
            bc.setPrice(this.price);
            return bc;
        }
    }
}

//客户端调用
public class test {
    public static void main(String[] args) {
        BarbecueCake b = BarbecueCake.builder()
                .name("烧烤饼")
                .price(6)
                .build();
        System.out.println(b);
    }
}

4.原型模式

通过拷贝这些原型创建新的对象。

public class User implements Cloneable {
    private String name;
    private Integer age;

    public User() { }

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object obj) {
        return super.equals(obj);
    }

    @Override
    protected User clone() throws CloneNotSupportedException {
        return new User(this.name,this.age);
    }

    public static void main(String[] args) throws CloneNotSupportedException {
        User user1 = new User("张三", 6);
        User userClone = user1.clone();
        user1.setAge(99);
        System.out.println(user1==userClone);//false
        System.out.println(user1);//User{name='张三', age=99}
        System.out.println(userClone);//User{name='张三', age=6}
    }
}

5.单例模式

注意:

  • 1、单例类只能有一个实例。

  • 2、单例类必须自己创建自己的唯一实例。

  • 3、单例类必须给所有其他对象提供这一实例。

5.1懒汉式

/**
 * 懒汉式 -- 线程不安全
 */
public class SingletonLayze {
    private static SingletonLayze singleton;
    private SingletonLayze(){}

    public static SingletonLayze getSingleton(){
        if (singleton==null){
            return new SingletonLayze();
        }
        return singleton;
    }
}

/**
 * 懒汉式 -- 线程安全
 */
public class SingletonLayze2 {
    private static SingletonLayze2 singletonLayze2;
    private SingletonLayze2(){}

    public static synchronized SingletonLayze2 getSingletonLayze2(){
            if (singletonLayze2==null){
                return new SingletonLayze2();
            }
            return singletonLayze2;
    }
}

5.2饿汉式

/**
 * 饿汉式
 */
public class SingletonHungry {
    private static SingletonHungry singletonHungry = new SingletonHungry();
    private SingletonHungry(){}

    public static SingletonHungry getInstance(){
        return singletonHungry;
    }
}

5.3双重检锁

public class Singleton {
    private volatile static  Singleton singleton;
    private Singleton(){}
    public static Singleton getInstance(){
        if (singleton==null){
            synchronized (Singleton.class){
                if (singleton==null){
                    return new Singleton();
                }
            }
        }
        return singleton;
    }
}

5.4登记式

public class SingletonIner {
    private static class SingletonHold{
        private static final SingletonIner Instance=new SingletonIner();
        private SingletonHold(){}
        public static SingletonIner getInstance(){
            return SingletonHold.Instance;
        }
    }

    public static void main(String[] args) {
        SingletonIner singletonIner = new SingletonIner();
        SingletonIner singletonIner1 = new SingletonIner();
        System.out.println(singletonIner==singletonIner1);
    }
}

5.5枚举、

public enum  SingletonEnum {
    INSTANCE;
    public void whateverMethod(){}
}

一般情况下,不建议使用第 1 种和第 2 种懒汉方式,建议使用第 3 种饿汉方式。只有在要明确实现 lazy loading 效果时,才会使用第 5 种登记方式。如果涉及到反序列化创建对象时,可以尝试使用第 6 种枚举方式。如果有其他特殊的需求,可以考虑使用第 4 种双检锁方式。