惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

V
Visual Studio Blog
N
Netflix TechBlog - Medium
GbyAI
GbyAI
大猫的无限游戏
大猫的无限游戏
博客园 - 三生石上(FineUI控件)
T
Tailwind CSS Blog
IT之家
IT之家
博客园 - Franky
雷峰网
雷峰网
博客园 - 聂微东
腾讯CDC
M
MIT News - Artificial intelligence
B
Blog RSS Feed
博客园_首页
罗磊的独立博客
S
SegmentFault 最新的问题
I
InfoQ
博客园 - 叶小钗
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
阮一峰的网络日志
阮一峰的网络日志
D
Docker
宝玉的分享
宝玉的分享
B
Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报

Jiajun的技术笔记

你好,2026! TiDB 源码阅读(六):TiDB Coprocessor 源码解析 性能优化的核心思想 TiDB 源码阅读(五):索引 TiDB 源码阅读(四):AST、逻辑计划、物理计划 CockroachDB Serverless Architecture podman 无故退出 Cursor Control-L (CTRL-L) Keyboard Shortcuts in Terminal Replace docker with podman Using xmonad with xfce4 A RC script for freebsd frpc 自己动手写一个k8s controller AI 会取代你的(编程)岗位吗? 自建DERP服务器提升Tailscale连接速度(使用Nginx转发) 自动升级Docker容器 再读《程序员修炼之道-从小工到专家》 让浏览器下载文件 再读《软件随想录》/《黑客与画家》/《软技能》 HTTP 压力测试中的 Coordinated Omission 2的补码 编程语言中的 context 是什么? flutter macOS 构建出错 Flatpak 使用小记 Golang CAS 操作是怎么实现的 PostgreSQL 当MQ来使用 Clash 结合 工作VPN 的网络设计 使用 PostgreSQL 搭建 JuiceFS PostgreSQL 配置优化和日志分析 有GitHub Copilot?那就可以搭建你的ChatGPT4服务 窗口函数的使用(以PG为例)
设计模式(1)- 深入浅出设计模式 阅读笔记
2017-01-21 · via Jiajun的技术笔记

将会使用Java和Python。其中Java实现可能比较业余,但是仍然使用Java, 因为很多设计模式在Java中更容易看清楚。

策略模式,观察者模式,装饰器模式,工厂模式,单例模式。

策略模式

策略模式其实就是一句话“针对接口编程,而不是针对实现编程”。接口是在Java中 可以是对应interface也可以是abstract类。接口其实是一个抽象概念。例如,c语言虽然 语法上不支持面向对象编程,但是其头文件的声明就相当于接口。

我们先来看Python版本的策略模式:

class SoundMixin:
    def sound(self):
        raise NotImplemented()


class DogSoundMixin(SoundMixin):
    def sound(self):
        print("wang wang...")


class DuckSoundMixin(SoundMixin):
    def sound(self):
        print("gua gua...")


class Animal:
    def make_noise(self):
        self.sound()


class Dog(DogSoundMixin, Animal):
    pass


class Duck(DuckSoundMixin, Animal):
    pass


if __name__ == "__main__":
    Dog().make_noise()
    Duck().make_noise()

运行一下:

$ python interface.py 
wang wang...
gua gua...

然后是Java版本:

// Sound.java
public interface Sound {
    public void sound();

}

// Animal.java
public abstract class Animal {
    abstract void sound();

    public void makeNoise() {
        sound();
    }
}

// Dig.java
public class Dog extends Animal implements Sound {
    public void sound() {
        System.out.println("wang wang...");
    }
}

// Duck.java
public class Duck extends Animal implements Sound {
    public void sound() {
        System.out.println("gua gua...");
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Animal animal;

        animal = new Dog();
        animal.makeNoise();

        animal = new Duck();
        animal.makeNoise();
    }
}

运行一下:

$ javac *.java && java Main 
wang wang...
gua gua...

观察者模式

观察者模式,就是消息订阅。消息提供者能够提供接口动态注册和注销,当消息到来, 消息提供者就会通知订阅者。典型的例子就是epoll,我们注册我们想要监听的事件, 例如描述符可读,当一个描述符可读时,epoll就会通知我们(这个例子也许不是特别 明显)。

我们先用Python实现一个:

class Observer:
    def __init__(self):
        self.callbacks = {}

    def register(self, name, func):
        self.callbacks[name] = func

    def cancell(self, name):
        if name in self.callbacks:
            self.callbacks.pop(name)

    def notify(self, event):
        for name, callback in self.callbacks.items():
            callback(name, event)


def callback(name, event):
    print("name(%s) with event: %s" % (name, event))


if __name__ == "__main__":
    observer = Observer()
    observer.register("marry", callback)
    observer.register("jack", callback)
    observer.register("lucy", callback)

    observer.notify("eat")

    observer.cancell("jack")
    observer.notify("sleep")

运行结果:

name(marry) with event: eat
name(jack) with event: eat
name(lucy) with event: eat
name(marry) with event: sleep
name(lucy) with event: sleep

再来Java:

// Observerable.java
import java.util.ArrayList;


public class Observerable {
    private ArrayList<Callback> observerables;
    public Observerable() {
        observerables = new ArrayList<Callback>();
    }

    public void register(Callback callback) {
        observerables.add(callback);
    }

    public void cancell(Callback callback) {
        int index = observerables.indexOf(callback);
        if (index >= 0) {
            observerables.remove(index);
        }
    }

    public void runAllCallbacks() {
        Callback callback;
        for (int i = 0; i < observerables.size(); i++) {
            callback = observerables.get(i);
            callback.callback("notifying " + i);
        }
    }
}

// Callback.java
public interface Callback {
    public void callback(String s);
}

// EatCallback.java
public class EatCallback implements Callback {
    public void callback(String s) {
        System.out.println("eat callback been called");
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Observerable observerable = new Observerable();

        observerable.register(new EatCallback());
        observerable.register(new EatCallback());
        observerable.register(new EatCallback());

        observerable.runAllCallbacks();
    }
}

运行一下:

$ javac *.java && java Main
eat callback been called
eat callback been called
eat callback been called

装饰器模式

装饰器模式,就是要在原有的函数上包装一层,让它能做更多的事情,但是却不用修改 原来的函数的代码。如果用Python的同学,相信无人不知无人不晓装饰器的威力,例如:

from contextlib import contextmanager


@contextmanager
def print_tag(tag):
    print("<%s>" % tag)
    yield
    print("</%s>" % tag)


with print_tag("body"):
    print("html body")
$ python decorator.py 
<body>
html body
</body>

然后再上Java实现:

// Origin.java
public class Origin {
    private String description = "Origin";

    public String getDescription() {
        return description;
    }
}

// Decorator.java
public class Decorator {
    Origin origin;

    public Decorator(Origin origin) {
        this.origin = origin;
    }

    public String getDescription() {
        return origin.getDescription() + " -> Decorator";
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        Origin origin = new Origin();
        Decorator decorator = new Decorator(origin);
        System.out.println(decorator.getDescription());
    }
}

运行一下:

$ javac *.java && java Main
Origin -> Decorator

工厂模式,抽象工厂

工厂模式和抽象工厂的差别在于,一个使用继承来实现,是一种金字塔关系,超类在上。 而抽象工厂虽然具体实现是金字塔关系,但是实际使用的时候只需要指定接口,所以 总体看来是一个倒金字塔关系。Python上不是很能看得出来,但是Java版本的很明显。 我们举个例子,现在有NFS和ISCSI的库供我们使用,我们希望能够做到指定 type就 返回给我们对应的实例。

先来Python版本:

TYPE_NFS = "nfs"
TYPE_ISCSI = "iscsi"


class Storage:
    pass


class NFS(Storage):
    pass


class ISCSI(Storage):
    pass


class StorageFactory:
    @staticmethod
    def instance(type):
        return NFS() if type == TYPE_NFS else ISCSI()


if __name__ == "__main__":
    print(StorageFactory.instance(TYPE_NFS).__class__)
    print(StorageFactory.instance(TYPE_ISCSI).__class__)

运行一下:

$ python factory.py 
<class '__main__.NFS'>
<class '__main__.ISCSI'>

再来Java:

// Storage.java
public interface Storage {
    public String getName();
}

// NFS.java
public class NFS implements Storage {
    public String getName() {
        return "it's NFS";
    }
}

// ISCSI.java
public class ISCSI implements Storage {
    public String getName() {
        return "it's ISCSI";
    }
}

// StorageFactory.java
public class StorageFactory {
    public Storage instance(String type) {
        if (type.equals("nfs")) {
            return new NFS();
        } else {
            return new ISCSI();
        }
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        StorageFactory storageFactory = new StorageFactory();
        System.out.println(storageFactory.instance("nfs").getName());
        System.out.println(storageFactory.instance("iscsi").getName());
    }
}

运行一下:

$ javac *.java && java Main
it's NFS
it's ISCSI

上面的Java代码是抽象工厂,其优点是简洁,调用类无需修改代码即可运行,但是每次 增加新的存储类型的时候,都需要修改一下instance方法。而工厂方法则无需如此:

// Storage.java
public abstract class Storage {
    public abstract String getName();
    public static Storage instance(String type) {
        return null;
    }
}

// NFS.java
public class NFS extends Storage {
    public String getName() {
        return "it's NFS";
    }

    public static Storage instance(String type) {
        return new NFS();
    }
}

// ISCSI.java
public class ISCSI extends Storage {
    public String getName() {
        return "it's ISCSI";
    }

    public static Storage instance(String type) {
        return new ISCSI();
    }
}

// Main.java
public class Main {
    public static void main(String[] args) {
        System.out.println(NFS.instance("nfs").getName());
        System.out.println(ISCSI.instance("iscsi").getName());
    }
}

所以工厂模式和抽象工厂的区别在于,工厂模式由子类决定具体实例化哪个类,而 抽象工厂自己决定初始化哪个类。

单例模式

单例模式是在开发中经常能用到的。单例,名字比较官方,如果改成“全局唯一”, 那就瞬间更好理解了。例如我们需要初始化一个全局唯一的配置类。

Python版本:

class Singleton(type):
    _instances = {}

    def __call__(cls, *args, **kwargs):
        if cls not in cls._instances:
            cls._instances[cls] = super().__call__(*args, **kwargs)
        return cls._instances[cls]


class SingletonConfig(metaclass=Singleton):
    def __init__(self):
        print("SingletonConfig initializing...")


if __name__ == "__main__":
    for i in range(10):
        SingletonConfig()

运行结果:

$ python singleton.py 
SingletonConfig initializing...

更多实现方式见:http://stackoverflow.com/questions/6760685/creating-a-singleton-in-python

Java版本:

// SingletonConfig.java
public class SingletonConfig {
    private static SingletonConfig singletonConfig;

    private SingletonConfig() {};

    public static synchronized SingletonConfig getConfig() {
        if (singletonConfig == null) {
            System.out.println("initializing a new Singleton Config");
            singletonConfig = new SingletonConfig();
        }
        return singletonConfig;
    }
}

// SingletonDemo.java
public class SingletonDemo {
    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            SingletonConfig config = SingletonConfig.getConfig();
        }
    }
}

运行结果:

$ javac *.java && java SingletonDemo 
initializing a new Singleton Config