【设计模式】常用的23种设计模式(一)

简介
常用的设计模式分三大类:
创建型模式(Creational Patterns)
结构型模式(Structural Patterns)
行为型模式(Behavioral Patterns)

本章主要来介绍下常用的5种创建型设计模式。

创建型模式(Creational Patterns)
创建型模式提供了一种创建对象同时又隐藏创建逻辑的方式,而不是使用new直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。

共5种:

  • 工厂方法模式(Factory Method Pattern)
  • 抽象工厂模式(Abstract Factory Pattern)
  • 单例模式(Singleton Pattern)
  • 建造者模式(Builder Pattern)
  • 原型模式(Prototype Pattern)

1、工厂方法模式(Factory Method Pattern)
在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。定义一个创建对象的接口,让其子类自己决定实例化哪一个工厂类,工厂模式使其创建过程延迟到子类进行。

工厂方法模式分以下三种:

1.1、普通工厂模式
建立一个工厂类,对实现统一接口的一些类进行实例的创建。

举例说明:
普通工厂模式类图

普通工厂模式类图

首先,创建统一接口:

public interface Sender {
    public void sender();
}

其次,创建统一接口的实现类:

public class EmailSender implements Sender {
    @Override
    public void sender() {
        System.out.println("send email ...");
    }
}

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

最后,创建工厂类:

public class SenderFactory {
    public Sender produce(String type) {
        if ("email".equals(type)) {
            return new EmailSender();
        } else if ("sms".equals(type)) {
            return new SmsSender();
        }
        return null;
    }
}

测试类:

public class SimpleFactoryTest {
    public static void main(String[] args) {
        SenderFactory factory = new SenderFactory();
        // 发送邮件
        Sender sender = factory.produce("email");
        sender.sender();
        // 发送短信
        Sender smsSender = factory.produce("sms");
        smsSender.sender();
    }
}

输出:

send email ...
send sms ...

1.2、多工厂方法模式
多工厂方法模式是对普通工厂模式的改进,如果传入的字符串有误,就不能正确创建对象,而多工厂方法模式是提供多个工厂方法,分别创建不同对象。
所以工厂类修改为:

public class SenderFactory {
    public Sender produceEmail() {
        return new EmailSender();
    }
    public Sender produceSms() {
        return new SmsSender();
    }
}

测试类:

public class ManyFactoryTest {
    public static void main(String[] args) {
        SenderFactory factory = new SenderFactory();
        // 发送邮件
        Sender sender = factory.produceEmail();
        sender.sender();
        // 发送短信
        Sender smsSender = factory.produceSms();
        smsSender.sender();
    }
}

输出:

send email ...
send sms ...

1.3、静态工厂方法模式
将上面多个工厂方法模式里面的工厂方法置为静态的,不需要创建工厂实例,直接调用即可。
则工厂类优化为:

public class SenderFactory {
    public static Sender produceEmail() {
        return new EmailSender();
    }
    public static Sender produceSms() {
        return new SmsSender();
    }
}

测试类:

public class StaticFactoryTest {
    public static void main(String[] args) {
        // 发送邮件
        Sender sender = SenderFactory.produceEmail();
        sender.sender();
        // 发送短信
        Sender smsSender = SenderFactory.produceSms();
        smsSender.sender();
    }
}

输出:

send email ...
send sms ...

至此,工厂方法模式介绍完毕,下面介绍抽象工厂模式。

2、抽象工厂模式(Abstract Factory Pattern)
工厂方法模式有一个问题,就是类的创建依赖于工厂类;也就是说如果想要拓展程序,必须对工厂类进行修改,这违反了开闭原则。如何解决这个问题,这时就用到了抽象工厂模式,创建多个工厂类,这样一旦需要增加新的功能,则只需要增加新的工厂类就可以,不需要修改之前的代码。

举例说明:

抽象工厂模式类图抽象工厂模式类图

首先,创建统一接口:

public interface Sender {
    public void sender();
}

其次,创建统一接口的实现类:

public class EmailSender implements Sender {
    @Override
    public void sender() {
        System.out.println("send email ...");
    }
}

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

public class SmsSender implements Sender {
    @Override
    public void send() {
        System.out.println("send sms ...");
    }
}

最后,对每个实现类分别创建工厂类:

public class EmailSenderFactory implements Provider {
    @Override
    public Sender produce() {
        return new EmailSender();
    }
}

public class SmsSenderFactory implements Provider {
    @Override
    public Sender produce() {
        return new SmsSender();
    }
}

public class IMSenderFactory implements Provider {
    @Override
    public Sender produce() {
        return new IMSender();
    }
}

测试类:

public class AbstFactoryTest {
    public static void main(String[] args) {
        // 发送Email
        Provider provider = new EmailSenderFactory();
        Sender sender = provider.produce();
        sender.send();

        // 发送Sms
        Provider smsProvider = new SmsSenderFactory();
        Sender smsSender = smsProvider.produce();
        smsSender.send();

        // 发送IM
        Provider imProvider = new IMSenderFactory();
        Sender imSender = imProvider.produce();
        imSender.send();
    }
}

输出:

send email ...
send sms ...
send IM ...

至此,抽象工厂模式就介绍完毕,下面开始介绍单例模式。

3、单例模式(Singleton Pattern)
在JVM内存中,只实例化一次。

单例类:

public class Singleton {

    /** 持有私有静态实例,防止被引用;此处赋值为null,目的是延迟加载 */
    private static Singleton instance = null;

    /** 私有化构造函数,防止直接实例化 */
    private Singleton() {}

    /** 获取实例对象 */
    public Singleton getInstance() {
        if (instance == null) {
            synchronized (instance) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    /** 如果该对象被用于序列化,此方法可以保证对象在序列化前后保持一致 */
    public Object readResolve() {
        return instance;
    }
}

此单例类防止了直接通过构造方法创建实例,同时在一定程度上解决了多线程环境下重复创建实例的问题。但由于Java创建对象和赋值操作是分两步执行的,而且JVM并不保证两个操作的顺序,即有可能出现先赋值,然后再创建实例。所以我们继续优化使用内部类来解决此问题。

单例类:

public class Singleton {

    /** 持有私有静态实例,防止被引用;此处赋值为null,目的是延迟加载 */
    private static Singleton instance = null;

    /** 私有化构造函数,防止直接实例化 */
    private Singleton() {}

    /** 使用内部类维护单例 */
    private static class SingletonFactory {
        private static Singleton singleton = new Singleton();
    }

    /** 获取实例对象 */
    public Singleton getInstance() {
        return SingletonFactory.singleton;
    }

    /** 如果该对象被用于序列化,此方法可以保证对象在序列化前后保持一致 */
    public Object readResolve() {
        return instance;
    }
}

至此,单例模式就介绍完毕,下面开始介绍建造者模式。

4、建造者模式(Builder Pattern)

工厂类模式提供的是创建单个类的模式,而建造者模式则是将各种产品集中起来进行管理,用来创建复合对象。工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象。

和前面的示例一样,一个Sender接口,两个实现类MailSender和SmsSender。
最后,建造者类如下:

public class Builder {
    private List<Sender> senderList = new ArrayList();
    public List<Sender> produceEmailSender(int count) {
        for (int i = 0; i < count; i++) {
            senderList.add(new EmailSender());
        }
        return senderList;
    }

    public List<Sender> produceSmsSender(int count) {
        for (int i = 0; i < count; i++) {
            senderList.add(new SmsSender());
        }
        return senderList;
    }
}

测试类:

public class BuilderTest {
    public static void main(String[] args) {
        Builder builder = new Builder();
        builder.produceEmailSender(5);
    }
}

所以与工厂模式的区别就是:工厂模式关注的是创建单个产品,而建造者模式则关注创建符合对象,多个部分。因此,是选择工厂模式还是建造者模式,依实际情况而定。

5、原型模式(Prototype Pattern)
通过复制现有实例来创建新的实例,即创建对象的克隆。

原型模式的本质就是clone
可以解决构建复杂对象的资源消耗问题,能在某些场景中提升构建对象的效率;还有一个重要用途是保护性拷贝,可以通过返回一个拷贝对象的形式,实现只读的限制;

原型类只需要实现Cloneable接口,覆写clone方法,此处的重点是调用super.clone()方法。

扩展:
深拷贝和浅拷贝
浅拷贝:将一个对象复制后,基本数据类型的变量重新创建,引用类型还指向原对象所指的。
深拷贝:将一个对象复制后,不论是基本数据类型还是引用类型,都是 重新创建的。

(完)

添加新评论