面向对象设计的 SOLID 原则

  • 单一责任原则(Single Responsibility Principle, SRP):一个类或者一个方法只做一件事。
  • 开放封闭原则(Open Closed Principle, OCP):对扩展开放,对修改关闭。换言之,一个类独立之后就不应该去修改它,而是以扩展的方式适应新需求。
  • 里氏替换原则(Liskov Substitution Principle, LSP):所有基类出现的地方都可以用派生类替换而不会程序产生错误。
  • 依赖倒置原则(Dependency Inversion Principle, DIP):高级模块不应该依赖低级模块,抽象不能依赖细节。
  • 接口分离原则(Interface Segregation Principle, ISP):类不应该依赖不需要的接口。

设计模式总览

单例模式(Singleton)

概念

  • 原理:保证一个类仅有一个实例,并提供一个访问它的全局访问点。

  • 优点
    • 全局只有一个实例,节省内存。
    • 全局只有一个访问点,便于数据同步控制和共享访问。
    • 单例可长驻内存,减少系统创建、销毁实例的开销。
  • 缺点
    • 比较难扩展,除非修改单例类的源代码。
    • 不能赋予单例太多职责,否则违反单一职责原则。
    • 多线程下更容易引发锁竞争,成为性能瓶颈。
  • 应用
    • 生成全局惟一的序列号;
    • 访问全局复用的惟一资源,如磁盘、总线等;
    • 单个对象占用的资源过多,如数据库等;
    • 系统全局统一管理,如Windows下的Task Manager;
    • 网站计数器。
  • 分类
    • 懒汉式:只有第一次访问单例的时候,才会初始化单例。本身是非线程安全的,但可以采用并发控制维护线程安全。优点是第一次访问慢,缺点是并发控制影响性能。懒汉式用的比较少。
    • 饿汉式:类一旦加载,就把单例初始化。天生就是线程安全的,不需要并发控制。优点是访问速度快,缺点是第一次访问前就实例化了,无意义地占用内存。饿汉式用的比较多。
  • 难点:防反射攻击。无论是懒汉式还是饿汉式,只要有构造方法,也无论构造方法是公开的还是私有的,都可以通过反射机制调用构造方法创建新实例,所以防反射攻击的一般方法是在构造方法里判断单例是否已经初始化。

Java 实现

  • 懒汉式:非线程安全
public class Singleton {

private static Singleton uniqueInstance;

private Singleton() {}

public static Singleton getUniqueInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
  • 饿汉式:线程安全
public class Singleton {

private Singleton1() {}

private static final Singleton single = new Singleton1();

public static Singleton getInstance() {
return single;
}
}
  • 懒汉式:方法锁,线程安全。锁竞争比较激烈,因为不管有没有实例化都要加锁。
public class Singleton {

private static Singleton uniqueInstance;

private Singleton() {}

public static synchronized Singleton getUniqueInstance() {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
return uniqueInstance;
}
}
  • 懒汉式:双重校验锁,线程安全。
    • 第一次判断 uniqueInstance == null 是为了在已经实例化后直接返回单例,不会无意义地加锁。
    • 第二次判断 uniqueInstance == null 是为了避免多个进程进入第一层if后,重复进行初始化,因为第一层if和synchronized之间不是临界区,所以可能有多个进程同时进入。
    • volatile 关键字禁止指令重排,保证线程安全。因为正常情况下new方法是先初始化实例再分配地址,指令重排后可能没初始化就分配了地址,导致uniqueInstance不为空但属性值都未初始化。
public class Singleton {

private volatile static Singleton uniqueInstance;

private Singleton() {}

public static Singleton getUniqueInstance() {
if (uniqueInstance == null) {
synchronized (Singleton.class) {
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}
}
  • 懒汉式:静态内部类,线程安全。使用静态内部类不需要加锁,性能比较好。
public class Singleton {

private Singleton() {}

private static class SingletonHolder {
private static final Singleton INSTANCE = new Singleton();
}

public static Singleton getUniqueInstance() {
return SingletonHolder.INSTANCE;
}
}
  • 防反射攻击的构造方法
public class Singleton {

private static Singleton uniqueInstance;

private Singleton() {
if(uniqueInstance != null){
throw new RuntimeException("Singleton instance has already created");
}
}

Python 实现

  • 因为Python的多线程本身就是垃圾,所以就不讨论线程安全了。

  • 使用模块:Python 的模块就是天然的单例模式,因为模块在第一次导入时,会生成 .pyc 文件,当第二次导入时,就会直接加载 .pyc 文件,而不会再次执行模块代码。

######## Singleton.py #############
class Singleton(object):
def foo(self):
pass

singleton = Singleton()
###################################

from Singleton import singleton
  • 使用装饰器:装饰器函数的字典里存储着它所标记的所有类的单例,当调用 a = A(x) 时,实际执行过程是 a = Singleton(A)(x) = _singleton(x) = _instance[A]
def Singleton(cls):
_instance = {}

def _singleton(*args, **kargs):
if cls not in _instance:
_instance[cls] = cls(*args, **kargs)
return _instance[cls]

return _singleton


@Singleton
class A(object):
def __init__(self, x):
self.x = x
  • 重写 init 或 new 函数:区别在于,new 函数负责创建实例,init 函数负责初始化实例,调用 s = Singleton() 时实际上是先调用 new 再调用 init,所以修改哪个都行。
######## 写法一 #############
class Singleton(object):

_instance = None

def __init__(self):
if not cls._instance:
raise("Singleton instance has already created")
else:
pass

@classmethod
def get_instance(cls):
if not cls._instance:
cls._instance = Singleton()
return cls._instance

######## 写法二 #############
class Singleton(object):

_instance = None

def __new__(cls, *args, **kwargs):
if not cls._instance:
cls._instance = super(Singleton, cls).__new__(cls)
return cls._instance

@classmethod
def get_instance(cls):
return cls._instance

简单工厂模式(Simple Factory)

概念

  • 原理:定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

  • 优点:
    • 实现了责任分割,工厂类中的判断逻辑可以决定创建哪个产品类的实例,客户端不负责创建产品实例,而仅仅是消费产品。
    • 客户端无须知道所创建的具体产品类的类名,只需要向工厂提供具体产品类的参数。
  • 缺点
    • 工厂类集中了所有产品创建逻辑,一旦工厂类罢工,整个系统都会瘫痪。
    • 系统扩展困难。一旦添加新产品就不得不修改工厂逻辑,破坏了开闭原则。
    • 产品类型较多时,工厂逻辑过于复杂,不利于系统的维护。
  • 适用场景:工厂类负责创建的对象比较少

Java 实现

public interface Product {}

public class ConcreteProduct implements Product {}
public class ConcreteProduct1 implements Product {}
public class ConcreteProduct2 implements Product {}


public class SimpleFactory {

public Product createProduct(int type) {
if (type == 1) {
return new ConcreteProduct1();
} else if (type == 2) {
return new ConcreteProduct2();
}
return new ConcreteProduct();
}
}

public class Client {

public static void main(String[] args) {
SimpleFactory simpleFactory = new SimpleFactory();
Product product = simpleFactory.createProduct(1);
}
}

Python 实现

# 定义虚类。相当于 Java 的接口
class Product(metaclass=ABCMeta):
@abstractmethod
def foo(self):
pass

class ConcreteProduct(Product):
def foo(self):
print("this is prodect 0")

class ConcreteProduct1(Product):
def foo(self):
print("this is prodect 1")

class ConcreteProduct2(Product):
def foo(self):
print("this is prodect 2")

class SimpleFactory():
def createProduct(self, prodectType):
if prodectType == 0:
return ConcreteProduct()
elif prodectType == 1:
return ConcreteProduct1()
else:
return ConcreteProduct1()

simpleFactory = SimpleFactory()
p = simpleFactory.createProduct(1)
p.foo()

工厂方法模式(Factory Method)

概念

  • 原理:工厂方法模式是简单工厂模式的进一步抽象,让一个类的实例化延迟到其子工厂类。

  • 优点:将创建对象的细节完全封装在具体工厂内部,在系统中加入新产品时,符合开闭原则。
  • 缺点:系统中类的个数将成对增加,每个具体产品类都对应一个具体工厂类,增加了系统的复杂度。
  • 适用场景
    • 日志记录器:记录可能记录到本地硬盘、系统事件、远程服务器等,用户可以选择记录日志到什么地方。
    • 数据库访问,当用户不知道最后系统采用哪一类数据库,以及数据库可能有变化时。
    • 设计一个连接服务器的框架,需要三个协议,”POP3”、”IMAP”、”HTTP”,可以把这三个作为产品类,共同实现一个接口。

Java 实现

public abstract class Factory {
abstract public Product factoryMethod();
public void doSomething() {
Product product = factoryMethod();
}
}

public class ConcreteFactory extends Factory {
public Product factoryMethod() {
return new ConcreteProduct();
}
}

public class ConcreteFactory1 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct1();
}
}

public class ConcreteFactory2 extends Factory {
public Product factoryMethod() {
return new ConcreteProduct2();
}
}

Python 实现

class Factory(metaclass=ABCMeta):
@abstractmethod
def createProduct(self):
pass

class ConcreteFactory(Factory):
def createProduct(self):
return ConcreteProduct()

class ConcreteFactory1(Factory):
def createProduct(self):
return ConcreteProduct1()

class ConcreteFactory2(Factory):
def createProduct(self):
return ConcreteProduct2()



factory = ConcreteFactory1()
p = factory.createProduct()
p.foo()

抽象工厂模式(Abstract Factory)

概念

  • 原理:抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形式,每个具体工厂可以创建一系列相关或相互依赖产品

  • 优点:当一个产品族中的多个对象被设计成一起工作时,能够保证客户端始终只使用同一个产品族中的对象。同时,增加新的产品族很方便,无须修改已有系统,符合开闭原则。
  • 缺点:增加新的产品等级结构麻烦,可能需要修改抽象层代码,违背了开闭原则。
  • 适用场景
    • QQ 换皮肤,一整套一起换。
    • 生成不同操作系统的程序。

Java 实现

public class AbstractProductA {}
public class AbstractProductB {}

public class ProductA1 extends AbstractProductA {}
public class ProductA2 extends AbstractProductA {}
public class ProductB1 extends AbstractProductB {}
public class ProductB2 extends AbstractProductB {}

public abstract class AbstractFactory {
abstract AbstractProductA createProductA();
abstract AbstractProductB createProductB();
}

public class ConcreteFactory1 extends AbstractFactory {
AbstractProductA createProductA() {
return new ProductA1();
}

AbstractProductB createProductB() {
return new ProductB1();
}
}

public class ConcreteFactory2 extends AbstractFactory {
AbstractProductA createProductA() {
return new ProductA2();
}

AbstractProductB createProductB() {
return new ProductB2();
}
}

public class Client {
public static void main(String[] args) {
AbstractFactory abstractFactory = new ConcreteFactory1();
AbstractProductA productA = abstractFactory.createProductA();
AbstractProductB productB = abstractFactory.createProductB();
}
}

Python 实现

生成器/建造者模式(Builder)

概念

  • 原理:封装了一个对象的构造过程,将复杂对象的构建过程与表示分离,使用相同的构建步骤作用于不同的子对象可以构建出不同表现形式的复杂对象。对于不太复杂的产品,可能只需要一个builder类就可以完成构建,如果产品过于复杂,可以先用一个builder类去生成产品的各个子部件,然后用director类将这些子部件组装成产品。

  • 优点
    • 把对象的构造步骤封装在builder类中,使得客户不必知道产品内部的组成细节。
    • 将构建代码和表示代码分开,便于对构建过程做精细控制。
  • 缺点:难以应对分步骤构建的需求变动。
  • 适用场景:需要生成的产品有复杂的内部结构和属性间的相互依赖,具有稳定的构建顺序。

Java 实现

Python 实现

######## 模拟快餐店点餐 ##########

class Burger():
name=""
price=0.0
def getPrice(self):
return self.price

class cheeseBurger(Burger):
def __init__(self):
self.name="cheese burger"
self.price=10.0

class spicyChickenBurger(Burger):
def __init__(self):
self.name="spicy chicken burger"
self.price=15.0

class Snack():
name = ""
price = 0.0
def getPrice(self):
return self.price

class chips(Snack):
def __init__(self):
self.name = "chips"
self.price = 6.0

class chickenWings(Snack):
def __init__(self):
self.name = "chicken wings"
self.price = 12.0

class Beverage():
name = ""
price = 0.0
def getPrice(self):
return self.price

class coke(Beverage):
def __init__(self):
self.name = "coke"
self.price = 4.0

class milk(Beverage):
def __init__(self):
self.name = "milk"
self.price = 5.0

# order 类和 orderBuilder 类在功能上几乎相同,但在逻辑上却是把订单的构建和表示相分离。
class order():
burger=""
snack=""
beverage=""
def __init__(self,orderBuilder):
self.burger=orderBuilder.bBurger
self.snack=orderBuilder.bSnack
self.beverage=orderBuilder.bBeverage

class orderBuilder():
bBurger=""
bSnack=""
bBeverage=""
def addBurger(self,xBurger):
self.bBurger=xBurger
def addSnack(self,xSnack):
self.bSnack=xSnack
def addBeverage(self,xBeverage):
self.bBeverage=xBeverage
def build(self):
return order(self)

# 如果订单结构很复杂,可以用 orderDirector 类封装 orderBuilder 类的功能。
class orderDirector():
order_builder=""
def __init__(self,order_builder):
self.order_builder=order_builder
def createOrder(self,burger,snack,beverage):
self.order_builder.addBurger(burger)
self.order_builder.addSnack(snack)
self.order_builder.addBeverage(beverage)
return self.order_builder.build()

order_Director = orderDirector()
order = order_Director.createOrder(spicyChickenBurger(), chips(), milk())

原型模式(Prototype)

概念

  • 原理:通过复制一个已经存在的实例来获得一个新的实例,把对象的创建逻辑封装在它自身里,有时也能减小创建此类实例带来的开销,被复制的实例就是所谓的原型。有深拷贝和浅拷贝两种实现方式。

  • 优点:在创建复杂或耗时的实例时,一定程度上减小了开销。
  • 缺点:原型类需要配置一个克隆方法,并且这个克隆方法需要对类的功能进行整体考虑。
  • 适用场景
    • 为了避免创建一个与产品类层次平行的工厂类层次时。
    • 当实例化的类是在运行时刻指定时。
    • 当一个系统应该独立于他的产品的创建、构成和表示时。也就是产品自己实现实例的创建。

Java 实现

public abstract class Prototype {
abstract Prototype shallowClone();
abstract Prototype deepClone();
}

public class ConcretePrototype extends Prototype implements Cloneable {

private String filed;

public ConcretePrototype(String filed) {
this.filed = filed;
}

@Override
Prototype shallowClone() {
// clone 是 Object 类的方法,所以用 super
return super.clone();
}

@Override
Prototype deepClone() {
return new ConcretePrototype(filed);
}
}

public class Client {
public static void main(String[] args) {
Prototype prototype = new ConcretePrototype("abc");
Prototype clone = prototype.myClone();
}
}

Python 实现

from copy import copy, deepcopy

class Prototype():
def shallowClone(self):
return copy(self)
def deepClone(self):
return deepcopy(self)

责任链模式(Chain Of Responsibility)

概念

  • 原理:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。

  • 优点
    • 降低了请求发出者和请求处理者之间的耦合。
    • 增强了对象指派职责的灵活性,通过改变链内的成员或者调动它们的次序,允许动态地新增或者删除责任。
    • 简化了对象,使得对象不需要知道链的结构。
    • 增加新的请求处理类很方便。
  • 缺点
    • 责任链过长会出现性能问题。
    • 不能保证请求一定被接收。
    • 另一方面,如果一个情求没有被正确处理也就是说不存在一个可以处理该请求的命令接收者而反复执行。
  • 适用场景:有多个对象可以处理一个请求,哪个对象处理该请求会在运行时刻自动确定。

Java 实现

public abstract class Handler {

protected Handler successor;

public Handler(Handler successor) {
this.successor = successor;
}

protected abstract void handleRequest(Request request);
}

public class ConcreteHandler1 extends Handler {

public ConcreteHandler1(Handler successor) {
super(successor);
}

@Override
protected void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE1) {
return;
}
if (successor != null) {
successor.handleRequest(request);
}
}
}

public class ConcreteHandler2 extends Handler {

public ConcreteHandler2(Handler successor) {
super(successor);
}

@Override
protected void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE2) {
return;
}
if (successor != null) {
successor.handleRequest(request);
}
}
}

public class Request {

private RequestType type;

public Request(RequestType type, String name) {
this.type = type;
}

public RequestType getType() {
return type;
}
}

public enum RequestType {
TYPE1, TYPE2
}

public class Client {

public static void main(String[] args) {

Handler handler1 = new ConcreteHandler1(null);
Handler handler2 = new ConcreteHandler2(handler1);

Request request1 = new Request(RequestType.TYPE1,);
handler2.handleRequest(request1);
}
}

Python 实现

class Handler():
successor = None
def setSuccessor(self, successor):
self.successor = successor
def handleRequest(self, request):
# 处理请求
pass

class ConcreteHandler1(Handler):
def handleRequest(self, request):
if request.requestType == 'type1':
return
elif self.successor != None:
self.successor.handleRequest(request)

class ConcreteHandler2(Handler):
def handleRequest(self, request):
if request.requestType == 'type2':
return
elif self.successor != None:
self.successor.handleRequest(request)

class Request():
def __init__(self, requestType):
self.requestType = requestType

req = request('type2')
handler1 = ConcreteHandler1()
handler2 = ConcreteHandler2()
handler1.setSuccessor(handler2)
handler1.handleRequest(req)

命令模式(Command)

概念

  • 原理:将请求封装成对象,将其作为命令调用者和接收者的中介,而抽象出来的命令对象又使得能够对一系列请求进行特殊操作。

  • 优点
    • 降低对象之间的耦合度。
    • 新的命令可以很容易地加入到系统中。
    • 可以比较容易地设计一个组合命令。
  • 缺点:可能会导致某些系统有过多的具体命令类,影响系统性能。
  • 适用场景
    • 系统需要将请求调用者和请求接收者解耦,使得调用者和接收者不直接交互。
    • 在不同的时刻指定、排列和执行请求。
    • 系统需要将一组操作组合在一起,即支持宏命令。
    • GUI 中每一个按钮都是一条命令。
    • 模拟 CMD。

Java 实现

// 模拟灯光遥控器。命令的发起者是人,接受者是灯,而中间负责调度和执行的是 Invoker 类。

public interface Command {
void execute();
}

public class LightOnCommand implements Command {
Light light;

public LightOnCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.on();
}
}

public class LightOffCommand implements Command {
Light light;

public LightOffCommand(Light light) {
this.light = light;
}

@Override
public void execute() {
light.off();
}
}

public class Light {

public void on() {
System.out.println("Light is on!");
}

public void off() {
System.out.println("Light is off!");
}
}

public class Invoker {
// 命令队列
private Command[] onCommands;
private Command[] offCommands;
private final int slotNum = 7;

public Invoker() {
this.onCommands = new Command[slotNum];
this.offCommands = new Command[slotNum];
}

public void setOnCommand(Command command, int slot) {
onCommands[slot] = command;
}

public void setOffCommand(Command command, int slot) {
offCommands[slot] = command;
}

public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
}

public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
}
}

public class Client {
public static void main(String[] args) {
Invoker invoker = new Invoker();
Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
// 绑定按键与命令
invoker.setOnCommand(lightOnCommand, 0);
invoker.setOffCommand(lightOffCommand, 0);
// 模拟按下按键
invoker.onButtonWasPushed(0);
invoker.offButtonWasPushed(0);
}
}

Python 实现

class LightOnCommand():
def __init__(self, light):
self.light = light
def execute(self):
light.on()

class LightOffCommand():
def __init__(self, light):
self.light = light
def execute(self):
light.off()

class Light():
def on(self):
print("Light is on!")
def off(self):
print("Light is off!")

class Invoker():
slotNum = 7
onCommands = [None] * slotNum
offCommands = [None] * slotNum
def setOnCommand(self, command, slot):
onCommands[slot] = command
def setOffCommand(self, command, slot):
offCommands[slot] = command
def onButtonWasPushed(self, slot):
onCommands[slot].execute()
def offuttonWasPushed(self, slot):
offCommands[slot].execute()

invoker = Invoker()
light = Light()
lightOnCommand = LightOnCommand(light)
lightOffCommand = LightOffCommand(light)
invoker.setOnCommand(lightOnCommand, 0)
invoker.setOffCommand(lightOffCommand, 0)
invoker.onButtonWasPushed(0)
invoker.offButtonWasPushed(0)

解释器模式(Interpreter)

概念

  • 原理:给定一个语言,定义它的文法的一种表示(分为终结符表达式和非终结符表达式),并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

  • 优点:易于改变和扩展文法,可以方便地实现一个简单的语言。
  • 缺点
    • 对于复杂文法难以维护,执行效率较低。
    • 可利用场景比较少。
    • 解释器模式会引起类膨胀。
    • 解释器模式采用递归调用方法。
  • 适用场景:鸡肋。

Java 实现

Python 实现

迭代器模式(Iterator)

  • 原理:提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。要使得聚合对象保持整洁和优雅,而不是说令聚合对象内部包含着各种遍历的方法,因此要将遍历的方法从聚合对象的指责中分离出来,按照不同的遍历需求分别封装成一个个专门遍历聚合对象内部数据的迭代器。

  • 优点
    • 在同一个聚合对象上可以定义多种遍历方式 简化了聚合类。
    • 由于引入了抽象层,增加新的聚合类和迭代器类都很方便,无须修改原有代码,符合开闭原则。
  • 缺点
    • 在增加新的聚合类时需要对应地增加新的迭代器类,类的个数成对增加。
    • 抽象迭代器的设计难度较大,需要充分考虑到系统将来的扩展。
    • 解释器模式会引起类膨胀。
    • 解释器模式采用递归调用方法。
  • 适用场景:需要遍历内部数据的对象都可以使用。

Java 实现

public interface Aggregate {
Iterator createIterator();
}

public class ConcreteAggregate implements Aggregate {

private Integer[] items;

public ConcreteAggregate() {}

@Override
public Iterator createIterator() {
return new ConcreteIterator<Integer>(items);
}
}

public interface Iterator<Item> {
Item next();
boolean hasNext();
}

public class ConcreteIterator<Item> implements Iterator {

private Item[] items;
private int position = 0;

public ConcreteIterator(Item[] items) {
this.items = items;
}

@Override
public Object next() {
return items[position++];
}

@Override
public boolean hasNext() {
return position < items.length;
}
}

public class Client {
public static void main(String[] args) {
Aggregate aggregate = new ConcreteAggregate();
Iterator<Integer> iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}

Python 实现

class Aggregate():
def createIterator(self):
pass

class ConcreteAggregate(Aggregate)
def __init__(self, items):
self.items = items
def createIterator(self):
return ConcreteIterator(items)

class Iterator():
def next(self):
pass
def hasNext(self):
pass

class ConcreteIterator(Iterator):
def __init__(self, items):
self.items = items
self.position = -1
def next(self):
position+=1
return items[position]
def hasNext(self):
return position < len(items)-1

aggregate = ConcreteAggregate([1,2,3,4,5])
iterator = aggregate.createIterator()
while iterator.hasNext():
print(iterator.next())

中介者模式(Mediator)

概念

  • 原理:用一个中介对象封装一系列的对象交互。中介者使各对象不需要显式地互相作用,从而使其耦合松散,并可以独立地改变它们之间的交互。很重要的一点就是中介者模式可以使得对象之间的关系数量急剧减少。

  • 优点
    • 降低了类的复杂度,将一对多转化成了一对一。
    • 各个类之间的解耦。
    • 符合迪米特原则(一个类对于其他类知道的越少越好)。
  • 缺点:中介者会庞大,变得复杂难以维护。
  • 适用场景:用于一组对象以定义良好但是复杂的方式进行通信的场合,以及想定制一个分布在多个类中的行为,而又不想生成太多的子类的场合。设计类图时,出现了网状结构时,可以考虑将类图设计成星型结构,这样就可以使用中介者模式了。如机场调度系统、路由系统,著名的MVC框架中,其中的C就是M和V的中介者。

Java 实现

  • 需要配合的所有 ConcreteColleague 实例都是 ConcreteMediator 的实例的属性,ConcreteMediator 负责调度这些属性对象。

Python 实现

备忘录模式(Memento)

概念

  • 原理:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原来保存的状态。(就是备份呗)

  • 优点
    • 给用户提供了一种状态恢复的实现机制。
    • 实现了信息的封装,用户不需要关心状态的保存细节。
  • 缺点:额外存储备忘录对象,资源消耗大。
  • 适用场景:实现撤销操作或事务回滚。

Java 实现

// 模拟保存游戏进度
public class GameCharacter {

private int life = 0;
private int attack = 0;
private int defense = 0;

public GameCharacter(int life, int attack, int defense) {
this.life = life;
this.attack = attack;
this.defense = defense;
}

public void saveState() {
return new Memento(this.life, this.attack, this.defense);
}

}

public class Memento {

private int life = 0;
private int attack = 0;
private int defense = 0;

public Memento(int life, int attack, int defense) {
this.life = life;
this.attack = attack;
this.defense = defense;
}
}

Python 实现

class GameCharacter():
def __init__(self,life,attack,defense):
self.life = life
self.attack = attack
self.defense = defense
def displayState(self):
print('Life:%d' % self.life)
print('Attack:%d' % self.attack)
print('Defence:%d' % self.defense)
def saveState(self):
return Memento(self.life, self.attack, self.defense)
def recoverState(self, memento):
self.life = memento.life
self.attack = memento.attack
self.defense = memento.defense

class Memento:
def __init__(self, life, attack, defense):
self.life = life
self.attack = attack
self.defense = defense

观察者模式(Observer)

概念

  • 原理:定义对象之间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象都得到通知并被自动更新。发生改变的对象称为观察目标(subject),被通知的对象称为观察者(observer)。一个观察目标可以对应多个观察者。

  • 优点
    • 实现了表示层和数据逻辑层的分离,在观察目标和观察者之间建立一个抽象的耦合。
    • 支持广播通信,简化了一对多系统设计的难度,符合开闭原则,增加新的观察者或观察目标很方便。
  • 缺点
    • 如果一个观察目标有很多的观察者,通知过程会十分耗时。
    • 如果观察者和观察目标之间存在循环依赖,可能导致系统崩溃。
    • 观察者无法知道观察目标是怎么发生变化的,仅仅只是知道其发生了变化。
  • 适用场景
    • 一个抽象模型有两个方面,其中一个方面依赖于另一个方面,即一种单向依赖的场景。
    • 一个对象的改变将导致其他某些对象发生改变,而无需知道具体哪些对象将发生改变,可以降低对象之间的耦合度。
    • 可以使用观察者模式创建一种链式触发机制,A对象的行为将影响B对象,B对象的行为将影响C对象。

Java 实现

// Java 内置了观察者模式的类和接口实现,封装了订阅、取消订阅、通知等操作。

public static class RealSubject extends Observable {

public void makeChanged() {
setChanged();
notifyObservers();
}
}

public static class RealObserver implements Observer {

@Override
public void update(Observable o, Object arg) {
System.out.println("调用了-->");
}
}

public static void main(String[] args) {
RealSubject subject = new RealSubject();
RealObserver observer = new RealObserver();
subject.addObserver(observer);
subject.makeChanged();
}

Python 实现

# 模拟火灾报警器。报警器、洒水器、拨号器是观察者,烟雾传感器是观察目标。

class Observer:
def update(self):
pass

class AlarmSensor(Observer):
def update(self,action):
print("Alarm Got: %s" % action)
self.runAlarm()
def runAlarm(self):
print("Alarm Ring...")

class WaterSprinker(Observer):
def update(self,action):
print("Sprinker Got: %s" % action)
self.runSprinker()
def runSprinker(self):
print("Spray Water...")

class EmergencyDialer(Observer):
def update(self,action):
print("Dialer Got: %s"%action)
self.runDialer()
def runDialer(self):
print("Dial 119...")

class Subject:
observers=[]
action=""
def addObserver(self,observer):
self.observers.append(observer)
def notifyAll(self):
for obs in self.observers:
obs.update(self.action)

class smokeSensor(Subject):
def setAction(self,action):
self.action=action
def isFire(self):
return True

if __name__=="__main__":
alarm=AlarmSensor()
sprinker=WaterSprinker()
dialer=EmergencyDialer()

smoke_sensor=smokeSensor()
smoke_sensor.addObserver(alarm)
smoke_sensor.addObserver(sprinker)
smoke_sensor.addObserver(dialer)

if smoke_sensor.isFire():
smoke_sensor.setAction("On Fire!")
smoke_sensor.notifyAll()

状态模式(State)

概念

  • 原理:允许一个对象在其内部状态改变时改变它的行为,即不同的状态对应了不同的行为,一个对象的行为取决于动态变化的状态。

  • 优点
    • 封装了转换规则,可以对状态转换代码进行集中管理,而不是分散在一个个业务方法中。
    • 将所有与某个状态有关的行为放到一个类中,方便增加新的状态,因为改变状态就自动改变了行为。
    • 允许状态转换逻辑与状态对象合成一体,而不是提供一个巨大的条件语句块。
    • 可以让多个环境对象共享一个状态对象,从而减少系统中对象的个数。
  • 缺点
    • 增加了系统中类和对象的个数,导致系统运行开销增大。
    • 状态模式的结构与实现都较为复杂,使用不当将导致程序结构和代码的混乱。
    • 对开闭原则的支持不太好,增加新的状态类需要修改负责状态转换的源代码,否则无法转换到新增状态,而且修改某个状态类的行为也需要修改对应类的源代码。
  • 适用场景
    • 行为依赖于状态,优化代码中大量与对象状态有关的条件语句。
    • 电梯、红绿灯、网上订单、文件审批等。

Java 实现

// 模拟宾馆的状态转换,有已预订、已入住、空闲三种状态。

public interface State {
void handle();
}

public class BookedState implements State {
@Override
public void handle() {
System.out.println("房间已预订!别人不能定!");
}
}

public class CheckedInState implements State {
@Override
public void handle() {
System.out.println("房间已入住!请勿打扰!");
}
}

public class FreeState implements State {
@Override
public void handle() {
System.out.println("房间空闲!!!没人住!");
}
}

public class HomeContext {
private State state;
public void setState(State s){
System.out.println("修改状态!");
state = s;
state.handle();
}
}

public class Client {
public static void main(String[] args) {
HomeContext ctx = new HomeContext();
ctx.setState(new FreeState());
ctx.setState(new BookedState());
}
}

Python 实现

  • 略~

策略模式(Strategy)

概念

  • 原理:定义一系列算法,将每一个算法封装起来,并让它们可以相互替换。策略模式让算法类可以独立于使用它的对象,提供了一种可插入式算法的实现方案,不需要将所有算法都硬编码到对象内部。策略模式和状态模式本质上是相同的,就看怎么理解状态转移和策略选择这两种行为的细微差别了。

  • 优点
    • 提供了对开闭原则的完美支持,可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
    • 提供了管理相关的算法族的办法。
    • 提供了一种可以替换继承关系的办法 可以避免多重条件选择语句。
    • 提供了一种算法的复用机制,不同的环境类可以方便地复用策略类。
  • 缺点
    • 策略类会增多。
    • 所有策略类都需要对外暴露。
  • 适用场景:一个系统需要动态地在几种算法中选择一种。

Java 实现

public interface Strategy {
public int doOperation(int num1, int num2);
}

public class OperationAdd implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}

public class OperationSubtract implements Strategy{
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}

public class Context {
private Strategy strategy;
public Context(Strategy strategy){
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2){
return strategy.doOperation(num1, num2);
}
}

public class StrategyPatternDemo {
public static void main(String[] args) {
Context context = new Context(new OperationAdd());
System.out.println("10 + 5 = " + context.executeStrategy(10, 5));

context = new Context(new OperationSubtract());
System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
}
}

Python 实现

  • 略~

模板方法模式(Template Method)

概念

  • 原理:定义一个操作中算法的框架,而将一些步骤延迟到子类中。模板方法模式使得子类不改变一个算法的结构即可重定义该算法的某些特定步骤,模板方法关注这样的一类行为,该类行为在执行过程中拥有大致相同的动作次序,只是动作在实现的具体细节上有所差异。

  • 优点
    • 封装不变部分,扩展可变部分。
    • 提取公共代码,便于维护。
    • 行为框架由父类控制,子类按需各自实现。
  • 缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
  • 适用场景:有多个子类共有的方法,且逻辑相同。

Java 实现

// 模拟泡茶和泡咖啡的流程

public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("boilWater");
}
void pourInCup() {
System.out.println("pourInCup");
}
}

public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Coffee.brew");
}
@Override
void addCondiments() {
System.out.println("Coffee.addCondiments");
}
}

public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Tea.brew");
}
@Override
void addCondiments() {
System.out.println("Tea.addCondiments");
}
}

public class Client {
public static void main(String[] args) {
CaffeineBeverage caffeineBeverage = new Coffee();
caffeineBeverage.prepareRecipe();
caffeineBeverage = new Tea();
caffeineBeverage.prepareRecipe();
}
}

Python 实现

  • 略~

访问者模式(Visitor)

概念

  • 原理:访问者封装了一些作用于某种数据结构中的各元素的操作,对元素的具体操作可以随着访问者改变而改变,实现了数据结构与数据操作的分离。

  • 优点
    • 符合单一指责,封装在访问者中的操作必定是与元素类本身关系不大且是易变的操作。
    • 扩展性好,因为被封装的操作通常都是易变的,所以可以在不改变元素类本身的前提下,实现对操作的扩展,元素类也可以通过接受不同的访问者来支持不同操作。
  • 缺点
    • 具体元素对访问者公布细节,违反了迪米特原则。
    • 具体元素变更比较困难,增加新的元素可能需要在每一个具体访问者类中增加相应的具体操作,违背了开闭原则。
    • 违反了依赖倒置原则,依赖了具体类,没有依赖抽象。
  • 适用场景:对象类型少但支持的操作很丰富,需要避免让这些操作污染对象的类。

Java 实现

public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}

public class Keyboard implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}

public class Monitor implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}

public class Mouse implements ComputerPart {
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}

public class Computer implements ComputerPart {
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for (int i = 0; i < parts.length; i++) {
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}

public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}

public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
@Override
public void visit(Computer computer) {
System.out.println("Displaying Computer.");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Displaying Mouse.");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Displaying Keyboard.");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Displaying Monitor.");
}
}

public class VisitorPatternDemo {
public static void main(String[] args) {
ComputerPart computer = new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}

Python 实现

  • 略~

空对象模式(Null)

概念

  • 原理:用返回空对象取代返回 NULL ,既可以避免抛出空指针异常,又可以在数据不可用的时候提供默认的行为。

  • 优点:略
  • 缺点:略
  • 适用场景:略

Java 实现

public abstract class AbstractCustomer {
protected String name;
public abstract boolean isNil();
public abstract String getName();
}

public class RealCustomer extends AbstractCustomer {
public RealCustomer(String name) {
this.name = name;
}
@Override
public String getName() {
return name;
}
@Override
public boolean isNil() {
return false;
}
}

public class NullCustomer extends AbstractCustomer {
@Override
public String getName() {
return "Not Available in Customer Database";
}
@Override
public boolean isNil() {
return true;
}
}

public class CustomerFactory {
public static final String[] names = {"Rob", "Joe", "Julie"};
public static AbstractCustomer getCustomer(String name){
for (int i = 0; i < names.length; i++) {
if (names[i].equalsIgnoreCase(name)){
return new RealCustomer(name);
}
}
return new NullCustomer();
}
}

public class NullPatternDemo {
public static void main(String[] args) {
AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob");
AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob");
AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie");
AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura");
System.out.println("Customers");
System.out.println(customer1.getName());
System.out.println(customer2.getName());
System.out.println(customer3.getName());
System.out.println(customer4.getName());
}
}

Python 实现

  • 略~

适配器模式(Adapter)

概念

  • 原理:为了解决接口不兼容的问题引进的一种接口兼容机制,通过提供一种适配器类将第三方提供的接口转换为客户希望的接口。

  • 优点
    • 将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,无须修改原有结构 增加了类的透明性和复用性。
    • 灵活性和扩展性非常好。
  • 缺点
    • 过多地使用适配器会让系统非常零乱,不易整体进行把握。
    • 由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
  • 适用场景
    • 系统需要使用现有的类,而此类的接口不符合系统的需要。
    • 美国电器 110V,中国 220V,就要有一个适配器将 110V 转化为 220V。
    • JAVA JDK 1.1 提供了 Enumeration 接口,而在 1.2 中提供了 Iterator 接口,想要使用 1.2 的 JDK,则要将以前系统的 Enumeration 接口转化为 Iterator 接口。
    • 在 LINUX 上运行 WINDOWS 程序。
    • JAVA 中的 jdbc。

Java 实现

public interface MediaPlayer {
public void play(String audioType, String fileName);
}

public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}

public class VlcPlayer implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {
System.out.println("Playing vlc file. Name: "+ fileName);
}
@Override
public void playMp4(String fileName) {}
}

public class Mp4Player implements AdvancedMediaPlayer{
@Override
public void playVlc(String fileName) {}
@Override
public void playMp4(String fileName) {
System.out.println("Playing mp4 file. Name: "+ fileName);
}
}

public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType){
if(audioType.equalsIgnoreCase("vlc") ){
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("vlc")){
advancedMusicPlayer.playVlc(fileName);
}else if(audioType.equalsIgnoreCase("mp4")){
advancedMusicPlayer.playMp4(fileName);
}
}
}

public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
if(audioType.equalsIgnoreCase("mp3")){
System.out.println("Playing mp3 file. Name: "+ fileName);
}
else if(audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")){
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
}
else{
System.out.println("Invalid media. "+audioType + " format not supported");
}
}
}

public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}

Python 实现

from abc import abstractmethod,ABCMeta

class MediaPlayer(metaclass=ABCMeta):
@abstractmethod
def play(self, strAudioType, strFilename):
pass

class AdvancedMediaPlayer(metaclass=ABCMeta):
@abstractmethod
def playVlc(self,strFilename):
pass
@abstractmethod
def playMp4(self,strFilename):
pass

class VlcPlayer(AdvancedMediaPlayer):
def playVlc(self,strFilename):
print("Playing vlc file. Name: "+strFilename)
def playMp4(self,strFilename):
pass
class Mp4Player(AdvancedMediaPlayer):
def playVlc(self,strFilename):
pass
def playMp4(self,strFilename):
print("Playing MP4 file. Name: " + strFilename)

class MediaAdapter(MediaPlayer):
advancedMusicPlayer = None
def __init__(self,strAudioType):
strAudioType = str.lower(strAudioType)
if strAudioType == "vlc" :
self.advancedMusicPlayer = VlcPlayer()
elif strAudioType == "mp4" :
self.advancedMusicPlayer = Mp4Player()
def play(self,strAudioType,strFilename):
if strAudioType == "vlc" :
self.advancedMusicPlayer.playVlc(strFilename)
elif strAudioType == "mp4" :
self.advancedMusicPlayer.playMp4(strFilename)

class AudioPlayer(MediaPlayer):
mediaAdapter = None
def play(self,strAudioType,strFilename):
strAudioType = str.lower(strAudioType)
if strAudioType == "mp3" :
print("Playing mp3 file. Name: "+ strFilename)
elif (strAudioType == "vlc") or (strAudioType == "mp4") :
self.mediaAdapter = MediaAdapter(strAudioType)
self.mediaAdapter.play(strAudioType,strFilename)
else :
print("Invalid media. "+ strAudioType + " format not supported.")

if __name__ == '__main__':
audioPlayer = AudioPlayer()

audioPlayer.play("mp3","beyond the horizon.mp3")
audioPlayer.play("mp4","alone.mp4")
audioPlayer.play("vlc", "far far away.vlc")
audioPlayer.play("avi", "mind me.avi")

桥接模式(Bridge)

概念

  • 原理:有些类在功能设计上要求自身包含两个或两个以上变化的因素,比如对于一杯咖啡,咖啡杯的大小和是否加奶为两个变化因素,使得这杯咖啡在这两个维度上发生变化。桥接模式是将抽象部分与它的实现部分解耦,使得两者都能够独立变化适应业务需求,两个部分中的任何一部分发生变化时都不会影响对方。

  • 优点
    • 分离了抽象接口与其实现部分,可以取代多层继承方案,将类之间的静态继承关系转换为动态的对象组合关系,极大地减少了子类的个数。
    • 提高了系统的可扩展性,在两个变化维度中任意扩展一个维度,不需要修改原有系统,符合开闭原则。
  • 缺点:增加系统的理解与设计难度,由于关联关系建立在抽象层,要求开发者一开始就针对抽象层进行设计与编程。
  • 适用场景
    • 如果一个系统需要在构件的抽象化角色和具体化角色之间增加更多的灵活性,避免在两个层次之间建立静态的继承联系,通过桥接模式可以使它们在抽象层建立一个关联关系。
    • 对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用。
    • 一个类存在两个独立变化的维度,且这两个维度都需要进行扩展。

Java 实现

  • 略~

Python 实现

# 用不同的笔画不同的图形,笔和图形是相互独立的,在基类之间建立关联后,就可以用对象组合的方式实现笔和图形的各种组合,而不需要让笔去继承所有图形类。
class Shape:
name=""
param=""
def __init__(self,*param):
pass
def getName(self):
return self.name
def getParam(self):
return self.name,self.param

class Pen:
shape=""
type=""
def __init__(self,shape):
self.shape=shape
def draw(self):
pass

class Rectangle(Shape):
def __init__(self,long,width):
self.name="Rectangle"
self.param="Long:%s Width:%s"%(long,width)
print("Create a rectangle:%s"%self.param)

class Circle(Shape):
def __init__(self,radius):
self.name="Circle"
self.param="Radius:%s"%radius
print("Create a circle:%s"%self.param)

class NormalPen(Pen):
def __init__(self,shape):
Pen.__init__(self,shape)
self.type="Normal Line"
def draw(self):
print("DRAWING %s:%s----PARAMS:%s"%(self.type,self.shape.getName(),self.shape.getParam()))

class BrushPen(Pen):
def __init__(self,shape):
Pen.__init__(self,shape)
self.type="Brush Line"
def draw(self):
print("DRAWING %s:%s----PARAMS:%s" % (self.type,self.shape.getName(), self.shape.getParam()))

if __name__=="__main__":
normal_pen=NormalPen(Rectangle("20cm","10cm"))
brush_pen=BrushPen(Circle("15cm"))
normal_pen.draw()
brush_pen.draw()

组合模式(Composite)

概念

  • 原理:将对象组合成树形结构以表示部分和整体的层次结构,使得用户对单个对象和组合对象的使用具有一致性。主要用来处理具有容器特征的对象,它们即充当对象又可以作为容器包含其他多个对象。

  • 优点:对节点增删和调用非常自由和方便。
  • 缺点:在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
  • 适用场景
    • 希望把对象表示分成部分-整体层次结构,或希望用户忽略组合对象与单个对象的不同。

Java 实现

public class Employee {
private String name;
private String dept;
private int salary;
private List<Employee> subordinates;

public Employee(String name,String dept, int sal) {
this.name = name;
this.dept = dept;
this.salary = sal;
subordinates = new ArrayList<Employee>();
}

public void add(Employee e) {
subordinates.add(e);
}

public void remove(Employee e) {
subordinates.remove(e);
}

public List<Employee> getSubordinates(){
return subordinates;
}

public String toString(){
return ("Employee :[ Name : "+ name
+", dept : "+ dept + ", salary :"
+ salary+" ]");
}
}

public class CompositePatternDemo {
public static void main(String[] args) {
Employee CEO = new Employee("John","CEO", 30000);

Employee headSales = new Employee("Robert","Head Sales", 20000);

Employee headMarketing = new Employee("Michel","Head Marketing", 20000);

Employee clerk1 = new Employee("Laura","Marketing", 10000);
Employee clerk2 = new Employee("Bob","Marketing", 10000);

Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
Employee salesExecutive2 = new Employee("Rob","Sales", 10000);

CEO.add(headSales);
CEO.add(headMarketing);

headSales.add(salesExecutive1);
headSales.add(salesExecutive2);

headMarketing.add(clerk1);
headMarketing.add(clerk2);

System.out.println(CEO);
for (Employee headEmployee : CEO.getSubordinates()) {
System.out.println(headEmployee);
for (Employee employee : headEmployee.getSubordinates()) {
System.out.println(employee);
}
}
}
}

Python 实现

  • 略~

装饰器模式(Decorator)

概念

  • 原理:动态地给一个对象增加一些额外的职责。就扩展功能而言,装饰模式提供了一种比使用子类更加灵活的替代方案,因为只针对某个对象而不是对象所属的类。

  • 优点
    • 装饰模式比继承更加灵活,不会导致类的个数急剧增加。
    • 可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的具体装饰类,从而实现不同的行为。
    • 可以对一个对象进行多次装饰。
    • 具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,且原有类库代码无须改变,符合开闭原则。
  • 缺点
    • 多层装饰比较复杂。
    • 使用装饰模式进行系统设计时将产生很多小对象,大量小对象的产生势必会占用更多的系统资源。
  • 适用场景:代替继承,更灵活地增加和删除功能。

Java 实现

public interface Shape {
void draw();
}

public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Rectangle");
}
}

public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Shape: Circle");
}
}

public abstract class ShapeDecorator implements Shape {
protected Shape decoratedShape;
public ShapeDecorator(Shape decoratedShape){
this.decoratedShape = decoratedShape;
}
public void draw(){
decoratedShape.draw();
}
}

public class RedShapeDecorator extends ShapeDecorator {
public RedShapeDecorator(Shape decoratedShape) {
super(decoratedShape);
}
@Override
public void draw() {
decoratedShape.draw();
setRedBorder(decoratedShape);
}
private void setRedBorder(Shape decoratedShape){
System.out.println("Border Color: Red");
}
}

public class DecoratorPatternDemo {
public static void main(String[] args) {
Shape circle = new Circle();
ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
System.out.println("Circle with normal border");
circle.draw();
System.out.println("Circle of red border");
redCircle.draw();
System.out.println("Rectangle of red border");
redRectangle.draw();
}
}

Python 实现

  • 略~

外观模式(Facade)

概念

  • 原理:外部与一个子系统的通信必须通过一个统一的外观对象进行,为子系统中的一组接口提供一个一致的界面,从而降低客户端与子系统的耦合度。其实就是高度封装。

  • 优点
    • 对客户屏蔽子系统组件,减少了客户处理的对象数目并使得子系统使用起来更加容易,实现了子系统与客户之间的松耦合关系。
    • 降低了大型软件系统中的编译依赖性,简化了系统在不同平台之间的移植过程。
  • 缺点:不能很好地限制客户使用子系统类,而且在不引入抽象外观类的情况下,增加新的子系统可能需要修改外观类或客户端的源代码,违背了开闭原则。
  • 适用场景:为一个复杂子系统提供一个简单接口。

Java 实现

public class SubSystem {
public void turnOnTV() {
System.out.println("turnOnTV()");
}
public void setCD(String cd) {
System.out.println("setCD( " + cd + " )");
}
public void startWatching(){
System.out.println("startWatching()");
}
}

public class Facade {
private SubSystem subSystem = new SubSystem();
public void watchMovie() {
subSystem.turnOnTV();
subSystem.setCD("a movie");
subSystem.startWatching();
}
}

public class Client {
public static void main(String[] args) {
Facade facade = new Facade();
facade.watchMovie();
}
}

Python 实现

  • 略~

享元模式(Flyweight)

概念

  • 原理:运用共享技术有效地支持大量细粒度对象的复用。

  • 优点:可以减少内存中对象的数量,使得相同或者相似的对象在内存中只保存一份,从而可以节约系统资源,提高系统性能。
  • 缺点
    • 需要分离出内部状态和外部状态,使得系统变得复杂。
    • 为了使对象可以共享,需要将享元对象的部分状态外部化,而读取外部状态将使得运行时间变长。
  • 适用场景:一个系统有大量相同或者相似的对象,造成内存的大量耗费,同时对象的大部分状态都可以外部化。

Java 实现

public interface Shape {
void draw();
}

public class Circle implements Shape {
private String color;
public Circle(String color){
this.color = color;
}
@Override
public void draw() {
System.out.println("Circle, Color : " + color);
}
}

public class ShapeFactory {
private static final HashMap<String, Shape> circleMap = new HashMap<>();
public static Shape getCircle(String color) {
Circle circle = (Circle)circleMap.get(color);
if(circle == null) {
circle = new Circle(color);
circleMap.put(color, circle);
System.out.println("Creating circle of color : " + color);
}
return circle;
}
}

public class FlyweightPatternDemo {
private static final String colors[] = { "Red", "Green", "Blue", "White", "Black" };
public static void main(String[] args) {
for(int i=0; i < 20; ++i) {
Circle circle =
(Circle)ShapeFactory.getCircle(getRandomColor());
circle.draw();
}
}
private static String getRandomColor() {
return colors[(int)(Math.random()*colors.length)];
}
}

Python 实现

  • 略~

代理模式(Proxy)

概念

  • 原理:引入一个代理对象,在客户端对象和目标对象之间起到中介的作用,负责去掉客户不能看到的内容和服务或者增添客户需要的额外的新服务。

  • 优点
    • 能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
    • 增加和更换代理类无须修改源代码,符合开闭原则,系统具有较好的灵活性和可扩展性。
  • 缺点
    • 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
    • 实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
  • 适用场景
    • 当客户端对象需要访问远程主机中的对象时可以使用远程代理。
    • 当需要用一个消耗资源较少的对象来代表一个消耗资源较多的对象,从而降低系统开销、缩短运行时间时可以使用虚拟代理。
    • 当需要为某一个被频繁访问的操作结果提供一个临时存储空间,以供多个客户端共享访问这些结果时可以使用缓冲代理。
    • 当需要控制对一个对象的访问,为不同用户提供不同级别的访问权限时可以使用保护代理。
    • 当需要为一个对象的访问提供一些额外的操作时可以使用智能引用代理。

Java 实现

// JDK 自带的动态代理

public interface Subject {
public int sellBooks();
public String speak();
}

public class RealSubject implements Subject{
@Override
public int sellBooks() {
System.out.println("卖书");
return 1 ;
}
@Override
public String speak() {
System.out.println("说话");
return "张三";
}
}

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class MyInvocationHandler implements InvocationHandler {
Subject realSubject ;
public MyInvocationHandler(Subject realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用代理类");
if(method.getName().equals("sellBooks")){
int invoke = (int)method.invoke(realSubject, args);
System.out.println("调用的是卖书的方法");
return invoke ;
}else {
String string = (String) method.invoke(realSubject,args) ;
System.out.println("调用的是说话的方法");
return string ;
}
}
}

import java.lang.reflect.Proxy;

public class Client {
public static void main(String[] args) {
Subject realSubject = new RealSubject();
MyInvocationHandler myInvocationHandler = new MyInvocationHandler(realSubject);
Subject proxyClass = (Subject) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Subject.class}, myInvocationHandler);
proxyClass.sellBooks();
proxyClass.speak();
}
}

Python 实现

  • 略~