java设计模式 - 创建型模式

一、工厂方法模式

工厂方法模式适用于出现了大量产品需要创建,并且又具有相同的接口时,就可以使用工厂方法模式进行产品的创建。实现工厂模式的方式又分为三种:普通工厂方法模式、多个工厂方法模式、静态工厂方法模式。

  1. 普通工厂方法模式,建立一个工厂类,对实现了同一接口的一些类进行实例的创建。以信息发送为例,假设我们有短信发送和邮件发送两种方式,以下为代码实现:
    Sender接口:
public interface Sender {
    void send();
}

邮件发送和短信发送的具体实现类:

public class MailSender implements Sender{
    public void send() {
        System.out.println("mail sender");
    }
}
public class SmsSender implements Sender{
    public void send() {
        System.out.println("sms sender");
    }
}

工厂类:

public class SendFactory {
    public Sender getSender(String type) {
        if ("mail".equals(type)) {
            return new MailSender();
        } else if ("sms".equals(type)) {
            return new SmsSender();
        } else {
            return null;
        }
    }
}

测试类:

public class FactoryTest {
    public static void main(String[] args) {
        SendFactory factory = new SendFactory();
        Sender mailSender = factory.getSender("mail");
        Sender smsSender = factory.getSender("sms");
        mailSender.send();
        smsSender.send();
    }
}

运行结果:

mail sender
sms sender
  1. 多个工厂方法模式,普通方法模式中,通过传入标志判断的方式容易导致错误。多个工厂方法模式则是为每个类提供创建实例的方法。改进普通工厂方法的缺陷。
    还以上面的消息发送为例,我们修改下工厂类:
public class SendFactory {
    // 获取邮件发送实例
    public Sender getMailSender() {
        return new MailSender();
    }
    //获取短信发送实例
    public Sender getSmsSender() {
        return new SmsSender();
    }
}

测试类相应改成调用这两个方法即可,比较简单易理解,就不列出了。

  1. 静态工厂方法模式,故名思意,该模式就是将多个工厂方法模式中的创建实例的方法改为静态的,这样就不需要创建工厂方法的实例进行调用。这里也不列出代码实现。该模式的应用有点像我们平时代码开发中的工具类。

二、抽象工厂模式

工厂方法模式会有一个问题,因为它实例的创建依赖工厂类,如果需要拓展,那么就要修改工厂类,违反开闭原则(对扩展开放,对修改关闭)。抽象工厂模式就可以解决该问题。
该模式是给每个类提供一个工厂方法,同时每个工厂方法类实现同一个工厂接口,UML图如下所示:

java设计模式 - 创建型模式_第1张图片
抽象工厂.png

SmsSender、MailSender以及他们实现的接口Sender和上面的一致。接下来我们只给出工厂类的代码实例。
工厂接口:

public interface Provider {
    Sender produce();
}

邮件和短信的工厂类:

public class SmsSendFactory implements Provider {
    public Sender produce() {
        return new SmsSender();
    }
}
public class MailSendFactory implements Provider {
    public Sender produce() {
        return new MailSender();
    }
}

创建实例只要调用不同工厂类的方法即可。如果我们需要增加一种消息方式(比如发微信)就无需修改现有的代码,只需要再增加一个对应的工厂类实现Provider接口,增加一个发送类实现Sender接口即可。不过感觉这种模式适合需要创建的产品总数不多的情况下,太多的话,就会有很多工厂类,感觉很冗余复杂。

三、单例模式

单例模式,即在一个jvm中,只有一个实例。单例模式一般分为饿汉式和懒汉式。

  1. 饿汉式,即在类加载的时候就创建实例,而不管实际是否需要。代码如下:
public class Singleton {
    private static Singleton singleton = new Singleton();
    private Singleton() {}
    public static Singleton getSingleton() {
        return singleton;
    }
}
  1. 懒汉式,与饿汉式相对,实例只是在第一次被调用的时候才创建。懒汉式有许多种方法,下面给出其中一个线程安全的写法:
public class Singleton {
    private static class init {
        private static Singleton singleton = new Singleton();
    }
    private Singleton() {
    }
    public static Singleton getSingleton() {
        return init.singleton;
    }
}

单例模式除了线程安全,还需要考虑序列化和反序列化的问题,上面的例子中,如果不额外实现序列化的话,那么每反序列化一次,就会创建一个实例,这就不是单例了。同时也需要防止有人使用反射强行调用私有构造器。对于此,EffectiveJava一书中,有建议使用枚举来实现单例,代码如下:

public enum Singleton2 {
    INSTANCE;
    private String name;
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
}

四、建造者模式

建造者模式和工厂模式有点不好区分,两者大体的区别是工厂模式关心的是一系列产品,而建造者模式关心的是单个产品的细节怎么构建。如车子,就工厂模式来说,它只关心各个品牌的车由哪些工厂建造,宝马由宝马工厂,奔驰由奔驰工厂。而建造者模式则会关心每个车子是由轮胎、发动机构成的。强调一个组成元素的构造过程。下面我们用造车子来进行代码实例展示。
汽车的蓝图:

public class CBlueprint {
    private String wheel;
    private String engine;

    public String getWheel() {
        return wheel;
    }

    public void setWheel(String wheel) {
        this.wheel = wheel;
    }

    public String getEngine() {
        return engine;
    }

    public void setEngine(String engine) {
        this.engine = engine;
    }
}

抽象构建者:

public interface CCarBuilder {
    void buildWheel();
    void buildEngine();
    CBlueprint buildBlueprint();
}

宝马和奔驰的具体构建类:

public class BwmBuilder implements CCarBuilder {
    private CBlueprint cBlueprint;

    public BwmBuilder() {
        cBlueprint = new CBlueprint();
    }

    public void buildWheel() {
        System.out.println("build bwm wheel");
        cBlueprint.setWheel("bwm wheel");
    }

    public void buildEngine() {
        System.out.println("build bwm engine");
        cBlueprint.setEngine("bwm engine");
    }

    public CBlueprint buildBlueprint() {
        return cBlueprint;
    }
}
public class BenzBuilder implements CCarBuilder {
    private CBlueprint cBlueprint;

    public BenzBuilder() {
        cBlueprint = new CBlueprint();
    }

    public void buildWheel() {
        System.out.println("build benz wheel");
        cBlueprint.setWheel("benz wheel");
    }

    public void buildEngine() {
        System.out.println("build benz engine");
        cBlueprint.setEngine("benz engine");
    }

    public CBlueprint buildBlueprint() {
        return cBlueprint;
    }
}

最终建造者:

public class Director {
    public CBlueprint buildCblueprint(CCarBuilder cCarBuilder) {
        cCarBuilder.buildEngine();
        cCarBuilder.buildWheel();
        return cCarBuilder.buildBlueprint();
    }
    public static void main(String[] args) {
        Director director = new Director();
        director.buildCblueprint(new BwmBuilder());
        director.buildCblueprint(new BenzBuilder());
    }
}

五、原型模式

原型模式采取复制原型对象的方法来创建对象的实例。使用原型模式创建的实例,具有与原型一样的数据。

public class Person implements Cloneable {
    @Override
    protected Person clone() {
        try {
            return (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

原型对象具体实现就是实现Cloneable接口,但是它没有实际的方法,只是对复制的一个标志。克隆还需要考虑浅复制和深复制。下面将举例说明:
浅复制:

public class Person implements Cloneable {
    private String name;
    private String sex;
    private List list;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    @Override
    protected Person clone() {
        try {
            return (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

深复制:

public class Person implements Cloneable {
    private String name;
    private String sex;
    private List list;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    public List getList() {
        return list;
    }

    public void setList(List list) {
        this.list = list;
    }

    @Override
    protected Person clone() {
        try {
            Person person = (Person) super.clone();
            List newList = new ArrayList();
            for (String str : this.list) {
                newList.add(str);
            }
            person.setList(newList);
            return person;
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
            return null;
        }
    }
}

说到复制,必须一提的是在EffectiveJava中,建议接口不要扩展(extend)Cloneable接口,为了继承而设计的类也不应该实现这个接口,具体原因可参见该书。

你可能感兴趣的:(java设计模式 - 创建型模式)