设计模式

  • 设计模式是无数前辈对代码开发的归纳总结;是解决特定问题的一系列套路
  • 设计模式不是语法规定,是一套用来提高代码可复用性、可维护性、可读性、稳健性以及安全性的解决方案
  • 设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解

设计模式分类

设计模式大致可以分为三种类型,共23种模式

  • 创建型模式:

    单例模式、工厂模式、抽象工厂模式、建造者模式、原型模式

  • 结构型模式:

    适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式

  • 行为型模式:

    模块方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式、访问者模式

单例模式

单例模式的特点:

构造器私有,只能通过一个静态方法获取唯一的类实例

常见场景:

  • Windows的任务管理器、回收站
  • 项目中,用于读取配置文件的类,一般只需要一个对象就够了
  • 网站或系统的计数器适合单例,以保证同步性
  • 数据库连接池类
  • JavaWeb中,每个Servlet是单例的
  • Spring中,每个Bean默认是单例的

单例模式的实现:

  • 饿汉式

    public class HungryMan {
        private HungryMan(){
      
        }
      
        private final static HungryMan HUNGRY_MAN = new HungryMan();
      
        public static HungryMan getInstance(){
            return HUNGRY_MAN;
        }
    }
    
  • 静态内部类

    public class Holder {
        private Holder(){
      
        }
      
        public static Holder getInstance(){
            return InnerClass.HOLDER;
        }
      
        public static class InnerClass{
            private static final Holder HOLDER = new Holder();
        }
    }
    
  • 懒汉式

    public class LazyMan {
        // 设置标记
        private static boolean flag = false;
      
        private LazyMan(){
            // 避免通过反射破坏单例
            synchronized (LazyMan.class){
                if(flag == false){
                    flag = true;
                }
                else {
                    throw new RuntimeException("ban reflection");
                }
            }
        }
      
        //避免指令重排
        private volatile static LazyMan LAZY_MAN;
      
        public static LazyMan getInstance(){
            if(LAZY_MAN == null){
                //双重检测 避免多线程场景破坏单例
                synchronized (LazyMan.class){
                    if(LAZY_MAN == null){
                        LAZY_MAN = new LazyMan();
                    }
                }
            }
            return LAZY_MAN;
        }
    }
    
  • 枚举

    Java的枚举Enum类,实现了单例;在开发中,在单例模式适用场景中,推荐直接使用Enum

    public enum Singleton {
        INSTANCE;
          
        public void doSomething(){
            System.out.println("doSomething");
        }
      
        // 调用单例对象
        public static void main(String[] args) {
            Singleton.INSTANCE.doSomething();
        }
    }
    

工厂模式

特点:

  • 实例化对象不使用new,用工厂方法代替
  • 对象的创建者与调用者分离

作用:

  • 降低耦合,Spring框架中的Bean就是由工厂创建的
  • 一定程度上减少代码重复,减少冗余
  • 对象的使用者不需要知道其具体的创建过程,故减少了因不熟悉创建逻辑而导致的错误

实现:

产品接口:

public interface Product {
    public void production();
}

不同产品:

public class ProductOne implements Product {
    @Override
    public void production() {
        System.out.println("产品1");
    }
}
public class ProductTwo implements Product {
    @Override
    public void production() {
        System.out.println("产品2");
    }
}

简单工厂模式:

生产同一等级结构中的任意产品(产品变动,工厂代码也要变动)

public class StaticFactory {
    public static Product getProduct(String productName){
        if(productName.equals("one")){
            return new ProductOne();
        }else if(productName.equals("two")){
            return new ProductTwo();
        }else {
            return null;
        }
    }
}

工厂方法模式:

由一个工厂接口和若干实现该接口的工厂类组成

产品变动,需要改动工厂类

public interface Factory {
    public void production();
}
public class ProductOneFactory implements Factory {
    @Override
    public void production() {
        System.out.println("产品1");
    }
}
public class ProductTwoFactory implements Factory {
    @Override
    public void production() {
        System.out.println("产品2");
    }
}

抽象工厂模式

特点:

  • 围绕一个超级工厂创建其他工厂,超级工厂可以视为工厂的工厂
  • 有一个创建一系列相关或者相互依赖对象的接口,无需指定它们具体的类

适用场景:

  • 一个继承体系中,存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束

实现案例:

  1. 手机工厂与路由器工厂

    public interface PhoneProduct {
        void start();
        void shutdown();
        void call();
    }
    
    public interface RouterProduct {
        void start();
        void shutdown();
        void wifi();
    }
    
  2. 手机产品与路由器产品

    public class XiaoMiPhone implements PhoneProduct {
        @Override
        public void start() {
            System.out.println("开启小米手机");
        }
       
        @Override
        public void shutdown() {
            System.out.println("关闭小米手机");
        }
       
        @Override
        public void call() {
            System.out.println("小米手机打电话");
        }
    }
    
    public class HuaWeiPhone implements PhoneProduct {
        @Override
        public void start() {
            System.out.println("开启华为手机");
        }
       
        @Override
        public void shutdown() {
            System.out.println("关闭华为手机");
        }
       
        @Override
        public void call() {
            System.out.println("华为手机打电话");
        }
    }
    
    public class XiaoMiRouter implements RouterProduct {
        @Override
        public void start() {
            System.out.println("开启小米路由器");
        }
       
        @Override
        public void shutdown() {
            System.out.println("关闭小米路由器");
        }
       
        @Override
        public void wifi() {
            System.out.println("小米路由器开wifi");
        }
    }
    
    public class HuaWeiRouter implements RouterProduct {
        @Override
        public void start() {
            System.out.println("开启华为路由器");
        }
       
        @Override
        public void shutdown() {
            System.out.println("关闭华为路由器");
        }
       
        @Override
        public void wifi() {
            System.out.println("华为路由器开wifi");
        }
    }
    
  3. 超级工厂

    public interface ProductFactory {
        // 手机工厂
        PhoneProduct phoneProduct();
        // 路由器工厂
        RouterProduct routerProduct();
    }
    
  4. 厂商工厂

    public class XiaoMiFactory implements ProductFactory {
        @Override
        public PhoneProduct phoneProduct() {
            return new XiaoMiPhone();
        }
       
        @Override
        public RouterProduct routerProduct() {
            return new XiaoMiRouter();
        }
    }
    
    public class HuaWeiFactory implements ProductFactory {
        @Override
        public PhoneProduct phoneProduct() {
            return new HuaWeiPhone();
        }
       
        @Override
        public RouterProduct routerProduct() {
            return new HuaWeiRouter();
        }
    }
    
  5. 用户使用

    public class User {
        public static void main(String[] args) {
            // 使用小米系列产品
            XiaoMiFactory xiaoMiFactory = new XiaoMiFactory();
            PhoneProduct xiaoMiPhone = xiaoMiFactory.phoneProduct();
            xiaoMiPhone.start();
            xiaoMiPhone.call();
            RouterProduct xiaoMiRouter = xiaoMiFactory.routerProduct();
            xiaoMiRouter.start();
            xiaoMiRouter.wifi();
       
            //华为系列产品
            HuaWeiFactory huaWeiFactory = new HuaWeiFactory();
            PhoneProduct huaWeiPhone = huaWeiFactory.phoneProduct();
            huaWeiPhone.start();
            huaWeiPhone.call();
            RouterProduct huaWeiRouter = huaWeiFactory.routerProduct();
            huaWeiRouter.start();
            huaWeiRouter.wifi();
        }
    }
    
  6. 类图结构

    HuaWeiFactory

  • 案例中,小米手机与小米路由器视为同一产品族;小米手机与华为手机视为同一产品等级

建造者模式

特点:

  • 将一个复杂对象的构建与它的表示分离
  • 同样的构建过程可以创建不同的表示

作用

  • 使用户在不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象;减少耦合

例子

  • 汽车类是一个非常复杂的类,其中有众多参数,用户直接创建十分繁琐,容易出错;加一个汽车建造者类(类似于工厂类),用户使用这个类,则可以用几个很少的参数,获得一个复杂的汽车对象
  • 在上述场景下,若有较多的地方创建了汽车对象,在没有建造者类时,统一修改它们的工作量变得不可想象;相反,可能只需要修改建造者一个类就可以了

实现案例

  • 产品类,假设需要给四个属性全部赋值,才能使该类对象可以正常使用

    public class Product {
        private String buildStep1;
        private String buildStep2;
        private String buildStep3;
        private String buildStep4;
      
        public String getBuildStep1() {
            return buildStep1;
        }
      
        public void setBuildStep1(String buildStep1) {
            this.buildStep1 = buildStep1;
        }
      
        public String getBuildStep2() {
            return buildStep2;
        }
      
        public void setBuildStep2(String buildStep2) {
            this.buildStep2 = buildStep2;
        }
      
        public String getBuildStep3() {
            return buildStep3;
        }
      
        public void setBuildStep3(String buildStep3) {
            this.buildStep3 = buildStep3;
        }
      
        public String getBuildStep4() {
            return buildStep4;
        }
      
        public void setBuildStep4(String buildStep4) {
            this.buildStep4 = buildStep4;
        }
      
        @Override
        public String toString() {
            return "Product{" +
                    "buildStep1='" + buildStep1 + '\'' +
                    ", buildStep2='" + buildStep2 + '\'' +
                    ", buildStep3='" + buildStep3 + '\'' +
                    ", buildStep4='" + buildStep4 + '\'' +
                    '}';
        }
    }
    
  • 抽象建造者类

    public abstract class Builder {
        abstract void buildStep1();
        abstract void buildStep2();
        abstract void buildStep3();
        abstract void buildStep4();
      
        abstract Product getProduct();
    }
    
  • 工人类,继承于抽象建造者类,用于具体产品的实现

    public class Worker extends Builder {
      
        private Product product;
      
        public Worker() {
            product = new Product();
        }
      
        @Override
        void buildStep1() {
            product.setBuildStep1("造轮子");
        }
      
        @Override
        void buildStep2() {
            product.setBuildStep2("造发动机");
        }
      
        @Override
        void buildStep3() {
            product.setBuildStep3("造车架");
        }
      
        @Override
        void buildStep4() {
            product.setBuildStep4("组装");
        }
      
        @Override
        Product getProduct() {
            return product;
        }
    }
    
  • 指挥者类,负责调度工人对象完成产品的生产,由他控制着产品的工序

    public class Director {
        public Product build(Builder builder){
            builder.buildStep1();
            builder.buildStep2();
            builder.buildStep3();
            builder.buildStep4();
      
            return builder.getProduct();
        }
    }
    
  • 消费者/用户,创建指挥者类,得到产品

    public class Comsumer {
        public static void main(String[] args) {
            Director director = new Director();
            Product product = director.build(new Worker());
      
            System.out.println(product.toString());
        }
    }
    
  • 类图结构