设计模式(1)- 深入浅出设计模式 阅读笔记

栏目: 后端 · 发布时间: 5年前

内容简介:将会使用Java和Python。其中Java实现可能比较业余,但是仍然使用Java, 因为很多设计模式在Java中更容易看清楚。策略模式,观察者模式,装饰器模式,工厂模式,单例模式。策略模式其实就是一句话“针对接口编程,而不是针对实现编程”。接口是在Java中 可以是对应interface也可以是abstract类。接口其实是一个抽象概念。例如,c语言虽然 语法上不支持面向对象编程,但是其头文件的声明就相当于接口。

将会使用 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

以上所述就是小编给大家介绍的《设计模式(1)- 深入浅出设计模式 阅读笔记》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

计算机程序设计艺术卷1:基本算法(英文版.第3版)

计算机程序设计艺术卷1:基本算法(英文版.第3版)

Donald E.Knuth / 人民邮电出版社 / 2010-10 / 119.00元

《计算机程序设计艺术》系列著作对计算机领域产生了深远的影响。这一系列堪称一项浩大的工程,自1962年开始编写,计划出版7卷,目前已经出版了4卷。《美国科学家》杂志曾将这套书与爱因斯坦的《相对论》等书并列称为20世纪最重要的12本物理学著作。目前Knuth正将毕生精力投入到这部史诗性著作的撰写中。想了解本书最新信息,请访http://www-cs-faculty.stanford.edu/~knut......一起来看看 《计算机程序设计艺术卷1:基本算法(英文版.第3版)》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具