【Java常见问题】基础知识(八)设计模式

146 阅读3分钟

设计模式是一种编码规范,笔者认为不同的设计模式没有对错好坏之分,只有是否符合当前项目的实际情况,所以这篇文章中重在了解其思想。对于不同的设计模式,笔者留意的重点也有所不同。这主要是基于我以往接触项目时的体会。有的能解决我过去的疑问,就多写一些,有的似乎还没有用到过,就简单略过。

image.png(图源维基百科)

一共有23种经典设计模式,分为创建型、结构型、行为型三类。以下先介绍这些模式中大多用到的基本原则。

七大原则

可以理解为类的六大原则+合成复用原则(尽量使用对象的组合或聚合而非继承)

  • 单一职责

一个类只做一件事情

  • 依赖倒置
    • 高层次的模块不依赖于低层次模块,两者都依赖于抽象
    • 具体实现依赖于抽象
  • 里式替换

子类对象可 替换(是覆盖而不是修改) 父类对象,而不影响父类固有的功能。 它是下述开放封闭原则的基础。

  • 开放封闭

对象或实体对扩展开放,对修改封闭

  • 接口隔离

使用多个专门接口比使用单个总接口要好

  • 迪米特法则(最少知识原则)

一个模块或对象应尽可能少地和其他对象或对象发生相互作用

接下来列举几个常用的设计模式。

单例模式

  • 含义:保证整个应用程序的生命周期中,任意时刻,单个类的实例都最多只存在一个
  • 应用场景:有真正的单一实例需求
  • 例子:打印机打印程序

工厂模式

  • 基本思想:实例化有大量公共接口的类,并动态决定将哪一个类实例化。
  • 使用场景: 维基百科是这么写的:

The Factory Method design pattern solves problems like:

  • How can an object be created so that subclasses can redefine which class to instantiate?
  • How can a class defer instantiation to subclasses?

笔者认为可理解为:延迟实例化。

  • 分类:简单工厂模式;工厂方法模式;抽象工厂模式

简单工厂模式

工厂类根据给定参数返回可能产品的类的示例,通常返回的类都有一个公共的父类和公共的方法。

工厂方法模式

以下是维基百科中提供的示例代码,通俗易懂。MazeGame就是其中的工厂类。

public abstract class Room {
    abstract void connect(Room room);
}

public class MagicRoom extends Room {
    public void connect(Room room) {}
}

public class OrdinaryRoom extends Room {
    public void connect(Room room) {}
}

public abstract class MazeGame {
     private final List<Room> rooms = new ArrayList<>();

     public MazeGame() {
          Room room1 = makeRoom();
          Room room2 = makeRoom();
          room1.connect(room2);
          rooms.add(room1);
          rooms.add(room2);
     }

     abstract protected Room makeRoom();
}


public class MagicMazeGame extends MazeGame {
    @Override
    protected MagicRoom makeRoom() {
        return new MagicRoom();
    }
}

public class OrdinaryMazeGame extends MazeGame {
    @Override
    protected OrdinaryRoom makeRoom() {
        return new OrdinaryRoom();
    }
}

MazeGame ordinaryGame = new OrdinaryMazeGame();
MazeGame magicGame = new MagicMazeGame();

抽象工厂模式

以下是Python示例代码:

from abc import ABC, abstractmethod
from sys import platform


class Button(ABC):
    @abstractmethod
    def paint(self):
        pass


class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"


class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"


class MacOSButton(Button):
    def paint(self):
        return "Render a button in a MacOS style"


class GUIFactory(ABC):
    @abstractmethod
    def create_button(self):
        pass


class LinuxFactory(GUIFactory):
    def create_button(self):
        return LinuxButton()


class WindowsFactory(GUIFactory):
    def create_button(self):
        return WindowsButton()


class MacOSFactory(GUIFactory):
    def create_button(self):
        return MacOSButton()


if platform == "linux":
    factory = LinuxFactory()
elif platform == "darwin":
    factory = MacOSFactory()
elif platform == "win32":
    factory = WindowsFactory()
else:
    raise NotImplementedError(f"Not implemented for your platform: {platform}")

button = factory.create_button()
result = button.paint()
print(result)

也可以将类本身作为工厂:

from abc import ABC, abstractmethod
from sys import platform


class Button(ABC):
    @abstractmethod
    def paint(self):
        pass


class LinuxButton(Button):
    def paint(self):
        return "Render a button in a Linux style"


class WindowsButton(Button):
    def paint(self):
        return "Render a button in a Windows style"


class MacOSButton(Button):
    def paint(self):
        return "Render a button in a MacOS style"


if platform == "linux":
    factory = LinuxButton
elif platform == "darwin":
    factory = MacOSButton
elif platform == "win32":
    factory = WindowsButton
else:
    raise NotImplementedError(f"Not implemented for your platform: {platform}")

button = factory()
result = button.paint()
print(result)

适配器模式

含义:将一个类的接口转化成另一种接口,从而使原本因接口不匹配而无法一起工作的两个类能一起工作。

观察者模式(发布-订阅模式)

  • 应用场景:维基百科中是这样写的:

The observer pattern addresses the following problems:

  • A one-to-many dependency between objects should be defined without making the objects tightly coupled.
  • When one object changes state, an open-ended number of dependent objects should be updated automatically.
  • An object can notify multiple other objects.
  • 个人理解:a不必和b强关联,但是a做了什么b可以立即知道;同理,不仅是b,还可以是bcd...,它们都可看做是一个“观察者”。
  • 示例代码:
import java.util.List;
import java.util.ArrayList;
import java.util.Scanner;

interface Observer {
    void update(String event);
}
  
class EventSource {
    List<Observer> observers = new ArrayList<>();
  
    void notifyObservers(String event) {
        observers.forEach(observer -> observer.update(event));
    }
  
    void addObserver(Observer observer) {
        observers.add(observer);
    }
  
    void scanSystemIn() {
        var scanner = new Scanner(System.in);
        while (scanner.hasNextLine()) {
            String line = scanner.nextLine();
            notifyObservers(line);
        }
    }
}

public class ObserverDemo {
    public static void main(String[] args) {
        System.out.println("Enter Text : ");
        var eventSource = new EventSource();
        
        eventSource.addObserver(event -> {
            System.out.println("Received response: " + event);
        });

        eventSource.scanSystemIn();
    }
}

测试结果如下:

image.png

参考资料

  • 维基百科
  • Java程序员笔试面试宝典