2 minute read

设计模式基于六大原则:

  • 开闭原则:对修改封闭,对扩展开放
  • 单一职责原则:一个类只做一件事
  • 里氏替换原则:继承时子类只扩展新功能,不破坏父类原有功能
  • 依赖倒置原则:细节依赖于抽象。抽象层放在程序设计的高层,程序细节的变化有底层的实现层来完成。
  • 迪米特法则:一个类不应知道自己操作的类的细节。
  • 接口隔离原则:客户端不应依赖它不需要的接口。让实现类只需依赖自己需要的接口方法。

创建型模式

关注于如何创建对象,将对象的创建与使用分离,降低耦合度。

1. 单例模式(Singleton)

一个类只有一个实例,且只有该类能自行创建这个实例,同时提供全局的指针访问这个实例。

优点

  • 内存中只有一个实例,减少内存开销
  • 避免对资源的多重占用(如写文件)

缺点

  • 没有接口,扩展困难

应用场景

  • 类需要频繁实例化又频繁销毁,如多线程的线程池等。
  • 对象需要被共享的场合,如数据库连接池。

代码实例

为了不让其他类创建该类的对象,那么只要让构造函数私有化,并且创建自定义的静态私有实例,并向外提供创建或者获取改静态私有实例的方法就行。

public class SingleObject {
    private static SingleObject INSTANCE = new SingleObject();
    //构造函数私有化
    private SingleObject() {
    }
	//对外提供获取实例的方法
    public static SingleObject getInstance() {
        return INSTANCE;
    }
}

线程安全的单例模式(双重校验锁)

public class ThreadSafeDoubleCheckLocking {
    private static volatile ThreadSafeDoubleCheckLocking INSTANCE;

    private ThreadSafeDoubleCheckLocking() {
        if (INSTANCE != null) {
            throw new IllegalStateException("Already initialized.");
        }
    }

    public static ThreadSafeDoubleCheckLocking getInstance() {
        var result = INSTANCE;
        if (result == null) {
            synchronized (ThreadSafeDoubleCheckLocking.class) {
                result = INSTANCE;
                if (result == null) {
                    INSTANCE = result = new ThreadSafeDoubleCheckLocking();
                }
            }
        }
        return result;
    }
}

线程安全的单例模式(懒加载)

public class ThreadSafeLazy {
    private static volatile ThreadSafeLazy INSTANCE;

    private ThreadSafeLazy() {
        if (INSTANCE != null) {
            throw new IllegalStateException("Already initialized.");
        }
    }

    public static synchronized ThreadSafeLazy getInstance() {
        if (result == null) {
            INSTANCE = new ThreadSafeDoubleCheckLocking();
        }
        return result;
    }
}

还有可以用枚举实现(推荐)

public enum SingleObject {
  	INSTANCE
}
    var demo1=SingleObject.INSTANCE;
    var demo2=SingleObject.INSTANCE;

2. 工厂模式(Factory, Simple Factory, Static Factory Method)

使用工厂(静态方法)封装类,隐藏实现细节,对外提供对象。

优点

  1. 一个调用者想创建一个对象,只要知道其名称就可以了
  2. 扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以
  3. 屏蔽产品的具体实现,调用者只关心产品的接口

缺点

每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,在一定程度上增加了系统的复杂度

应用场景

根据不同入参获得不同对象。

代码实例

食品工厂生产多种食品。

public interface Food{
    void produce();
}
public class Baozi implements Food {
    public void produce() {
        //生产包子
    }
}
public class Dumpling implements Food{
    public void produce() {
        // 生产饺子
    }
}
public class FoodFactory {
    public static Food getFood(String food) {
        if ("baozi".equals(food)) {
            new Baozi();
        } else if ("dumpling".equals(food)) {
            new Dumpling();
        }
    }
}
public class App{
    public static void main(String[] args) {
        FoodFactory.getFood("baozi");
        FoodFactory.getFood("dumpling");
    }
}

3. 抽象工厂模式(Abstract Factory)

抽象工厂模式就是对工厂模式的抽象。可能存在多种相似的工厂,提取这些工厂的特性。

优点

适用于横向拓展。(比如实例里面是食品工厂,那么可以加很多类似的可以生产食品的工厂)

缺点

不适合新增功能,比如抽象接口FoodFactory要新增接口,那么所有的具体工厂都需要实现

应用场景

不同操作系统的UI工具

代码实例

存在精灵王国与矮人王国,都存在国王、军队、城堡,实例化都是通过各自的工厂模式,因此可以进行抽象。

public interface Army {
    String print();
}

public interface King {
    String print();
}

public interface Castle {
    String print();
}
public class ElfArmy implements Army {
    // 具体实现
}

public class ElfKing implements King {
    // 具体实现
}

public class ElfCastle implements Castle {
    // 具体实现
}

对王国的抽象

public interface KingdomFactory {
    Castle createCastle();

    King createKing();

    Army createArmy();
}
public class ElfKingdomFactory implements KingdomFactory {
    // 具体实现
}

4. 建造者模式(Builder)

用于创建过程稳定,但配置多变的对象

优点

建造者独立,易扩展

缺点

产品需要有共同点

应用场景

一个复杂对象(由多个子对象组合而成)的创建

代码实例

RPG游戏创建角色

public final class Hero {
    private final Profession profession;
    private final String name;
    private final HairType hairType;
    private final HariColor hariColor;
    private final Armor armor;
    private final Weapon weapon;

    private Hero(Builder builder) {
        this.profession = builder.profession;
        this.name = builder.name;
        this.hairColor = builder.hairColor;
        this.hairType = builder.hairType;
        this.weapon = builder.weapon;
        this.armor = builder.armor;
    }
    
    public static class Builder {
        private final Profession profession;
        private final String name;
        private HairType hairType;
        private HairColor hairColor;
        private Armor armor;
        private Weapon weapon;

        public Builder(Profession profession, String name) {
            if (profession == null || name == null) {
                throw new IllegalArgumentException("profession and name can not be null");
            }
            this.profession = profession;
            this.name = name;
        }

        public Builder withHairType(HairType hairType) {
            this.hairType = hairType;
            return this;
        }

        public Builder withHairColor(HairColor hairColor) {
            this.hairColor = hairColor;
            return this;
        }

        public Builder withArmor(Armor armor) {
            this.armor = armor;
            return this;
        }

        public Builder withWeapon(Weapon weapon) {
            this.weapon = weapon;
            return this;
        }

        public Hero build() {
            return new Hero(this);
        }
    }
}
public class App{
    public static void main(String[] args) {
        var mage = new Hero.Builder(Profession.MAGE, "Riobard")
                .withHairColor(HairColor.BLACK)
                .withWeapon(Weapon.DAGGER)
                .build();
    }
}

5. 原型模式(Prototype)

需要创建大量相同或者相似对象

优点

  • 比重新new一个对象性能高

    缺点

  • 需要为每个类都配置一个clone方法

    应用场景

    很少单独出现,一般是结合工厂方法模式一起使用。

    代码实例

    Java提供了clone方法,只要类实现Cloneable就行了,非常简单(Java自带的方法是浅拷贝,只拷贝基本类型的参数,非基本类型的对象不拷贝。深拷贝需要实现Serializable)

    public class RealizeType implements Cloneable {
        
      public RealizeType() {
          System.out.println("具体原型创建成功");
      }
    
      @Override
      protected RealizeType clone() throws CloneNotSupportedException {
          System.out.println("具体原型复制成功");
          return (RealizeType) super.clone();
      }
    }
    
    public class Demo {
      public static void main(String[] args) throws CloneNotSupportedException {
          RealizeType realizetype=new RealizeType();
          //拷贝
          RealizeType clone = realizetype.clone();
      }
    }