前言:设计模式(Design pattern)代表了最佳的实践,通常被有经验的面向对象的软件开发人员所采用。设计模式是软件开发人员在软件开发过程中面临的一般问题的解决方案。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。由四人帮(GOF:Gang of Four)创建。

一. 设计模式简介

  • 设计模式基本要素

    模式名称、问题、解决方案、效果

  • 创建型模式

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

  • 结构型模式

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

  • 行为型模式

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

二. OOP七大原则

  • 开闭原则

    对扩展开放,对修改关闭。目的:降低维护带来的新风险。

  • 里氏替换原则

    子类可以扩展父类的方法,但不可以重写父类的方法。目的:防止继承泛滥。

  • 依赖倒置原则

    面向接口编程,不要面向实现编程。目的:有利于代码结构的升级扩展。

  • 单一职责原则

    一个类只干一件事。目的:便于理解。

  • 接口隔离原则

    要为各个类建立需要的专用接口。目的:高内聚,低耦合。

  • 迪米特法则

    只和朋友交流,不跟陌生人说话。目的:降低耦合度。

  • 合成复用原则

    先考虑用组合关系实现代码复用,其次才考虑用继承实现。比如,一个类的对象是另一个类的成员变量。目的:降低代码耦合。

三. 设计模式详解

3.1 单例模式

  • 饿汉式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    // 饿汉式单例(类产生时就实例化,易浪费内存资源)
    public class Hungry {

    private Hungry(){

    }

    private final static Hungry HUNGRY = new Hungry();

    public static Hungry getInstance(){
    return HUNGRY;
    }
    }
  • 懒汉式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    // 懒汉式单例
    public class LazyMan {

    private LazyMan() {
    System.out.println(Thread.currentThread().getName() + "ok");
    }

    private volatile static LazyMan lazyMan;

    // 双重检测锁模式 DLC懒汉式
    public static LazyMan getInstance() {
    if (lazyMan == null) {
    synchronized (LazyMan.class) {
    if (lazyMan == null) {
    lazyMan = new LazyMan(); // 不是原子性操作
    }
    }
    }
    return lazyMan;
    }

    public static void main(String[] args) {
    for (int i = 0; i < 10; i++) {
    new Thread(() -> {
    LazyMan.getInstance();
    }).start();
    }
    }
    }

3.2 工厂模式

  • 实现创建者和调用者分离

  • 实例化对象不用new,用工厂方法

  • 简单工厂模式(静态工厂)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    // 创建一个工厂
    // 新增一种车要改变工厂类代码,不满足开闭原则
    public class CarFactory {
    public static Car getCar(String car) {
    if (car.equals("五菱")) {
    return new WuLing();
    } else if (car.equals("特斯拉")) {
    return new Tesla();
    } else {
    return null;
    }
    }
    }

    public class Consumer {
    public static void main(String[] args) {
    // 从工厂获取实例化对象
    Car car1 = CarFactory.getCar("五菱");
    Car car2 = CarFactory.getCar("特斯拉");
    car1.name();
    car2.name();
    }
    }
  • 工厂方法模式

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    // 每加一个类,相对应加一个工厂类
    public class TeslaFactory implements CarFactory {
    @Override
    public Car getCar() {
    return new Tesla();
    }
    }

    public class WuLingFactory implements CarFactory {
    @Override
    public Car getCar() {
    return new WuLing();
    }
    }

    public class Consumer {
    public static void main(String[] args) {
    // 工厂
    Car car1 = new WuLingFactory().getCar();
    Car car2 = new TeslaFactory().getCar();
    car1.name();
    car2.name();
    }
    }

3.3 抽象工厂模式

  • 围绕一个超级工厂创建其他工厂,该超级工厂又称为其他工厂的工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    // 定义手机产品
    public interface PhoneProduct {
    void start();
    void shutdown();
    void callup();
    void sendSMS();
    }

    // 定义路由器产品
    public interface RouterProduct {
    void start();
    void shutdown();
    void openWifi();
    void setting();
    }

    // 实现产品,以华为手机为例
    public class HuaweiPhone implements PhoneProduct {
    @Override
    public void start() {
    System.out.println("开启华为手机");
    }
    @Override
    public void shutdown() {
    System.out.println("关闭华为手机");
    }
    @Override
    public void callup() {
    System.out.println("华为打电话");
    }
    @Override
    public void sendSMS() {
    System.out.println("华为发短信");
    }
    }

    // 抽象产品工厂
    public interface ProductFactory {
    // 生产手机
    PhoneProduct phoneProduct();
    // 生产路由器
    RouterProduct routerProduct();
    }

    // 实现工厂,以小米为例
    public class XiaomiFactory implements ProductFactory {
    @Override
    public PhoneProduct phoneProduct() {
    return new XiaomiPhone();
    }
    @Override
    public RouterProduct routerProduct() {
    return new XiaomiRouter();
    }
    }
  • 类图

    抽象工厂模式

3.4 建造者模式

  • 将一个复杂对象的构建和表示分离

  • 抽象工厂模式相当于汽车配件生产工厂,那么建造者模式就相当于汽车组装工厂

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    // 产品
    public class Product {
    private String buildA = "汉堡";
    private String buildB = "可乐";
    private String buildC = "薯条";
    private String buildD = "甜点";

    public String getBuildA() {
    return buildA;
    }

    public void setBuildA(String buildA) {
    this.buildA = buildA;
    }

    public String getBuildB() {
    return buildB;
    }

    public void setBuildB(String buildB) {
    this.buildB = buildB;
    }

    public String getBuildC() {
    return buildC;
    }

    public void setBuildC(String buildC) {
    this.buildC = buildC;
    }

    public String getBuildD() {
    return buildD;
    }

    public void setBuildD(String buildD) {
    this.buildD = buildD;
    }

    @Override
    public String toString() {
    return "Product{" +
    "buildA='" + buildA + '\'' +
    ", buildB='" + buildB + '\'' +
    ", buildC='" + buildC + '\'' +
    ", buildD='" + buildD + '\'' +
    '}';
    }
    }

    // 建造者
    public abstract class Builder {
    abstract Builder buildA(String msg); // 汉堡,这里返回Builder是方便链式调用

    abstract Builder buildB(String msg); // 可乐

    abstract Builder buildC(String msg); // 薯条

    abstract Builder buildD(String msg); // 甜点

    abstract Product getProduct();
    }

    // 工人,继承建造者
    public class Worker extends Builder {

    private Product product;

    public Worker() {
    product = new Product();
    }

    @Override
    Builder buildA(String msg) {
    product.setBuildA(msg);
    return this;
    }

    @Override
    Builder buildB(String msg) {
    product.setBuildB(msg);
    return this;
    }

    @Override
    Builder buildC(String msg) {
    product.setBuildC(msg);
    return this;
    }

    @Override
    Builder buildD(String msg) {
    product.setBuildD(msg);
    return this;
    }

    @Override
    Product getProduct() {
    return product;
    }
    }

    public class Test {
    public static void main(String[] args) {
    // 服务员
    Worker worker = new Worker();
    // 指挥工人(建造者),并获得产品
    Product product = worker.buildA("特斯拉").buildB("肯德基").getProduct();
    System.out.println(product.toString());
    }
    }

3.5 代理模式

  • 静态代理

    抽象角色:一般使用接口或者抽象类解决

    真实角色:被代理的角色

    代理角色:代理真实角色,做一些附属操作

    客户:访问代理对象的人

    代理模式

    优点:使真实角色操作更纯粹,把公共业务交给代理角色,方便集中管理

    缺点:一个真实角色会对应一个代理角色,代码量翻倍

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    // 租房(抽象角色)
    public interface Rent {
    void rent();
    }

    // 房东(真实角色)
    public class Host implements Rent{
    @Override
    public void rent() {
    System.out.println("房东要出租房子。");
    }
    }

    // 中介(代理角色)
    public class Proxy implements Rent {

    private Host host;

    public Proxy() {

    }

    public Proxy(Host host) {
    this.host = host;
    }

    @Override
    public void rent() {
    seeHouse();
    fee();
    host.rent();
    }

    // 看房
    public void seeHouse() {
    System.out.println("中介看房");
    }

    // 中介费
    public void fee() {
    System.out.println("收中介费");
    }
    }

    // 客户,访问代理
    public class Client {
    public static void main(String[] args) {
    Host host = new Host();
    // 代理,会做一些附属操作
    Proxy proxy = new Proxy(host);
    proxy.rent();
    }
    }
  • 动态代理

    代理类是动态生成的,角色与静态代理一致

    两大类:基于接口的动态代理、基于类的动态代理

    • 基于接口:JDK动态代理
    • 基于类:CGLIB动态代理
    • Java字节码:Javassist

    需要了解:Proxy 和 InvocationHandler 类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    // 用这个类,动态生成代理类
    public class ProxyInvocationHandler implements InvocationHandler {

    // 被代理的接口
    private Rent rent;

    public void setRent(Rent rent) {
    this.rent = rent;
    }

    // 得到代理类
    public Object getProxy() {
    return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    // 处理代理实例,并返回结果
    // 动态代理的本质,使用反射实现
    seeHouse();
    System.out.println("执行了" + method.getName() + "方法");
    Object result = method.invoke(rent, args);
    return result;
    }

    public void seeHouse() {
    System.out.println("中介带看房子");
    }
    }

    // 客户,调用代理
    public class Client {
    public static void main(String[] args) {
    // 真实角色
    Host host = new Host();
    // 代理角色
    ProxyInvocationHandler pih = new ProxyInvocationHandler();
    pih.setRent(host);

    Rent proxy = (Rent) pih.getProxy(); // 这里的proxy是动态生成的
    proxy.rent();
    }
    }