参考资料:
用途:
- 减少垃圾代码,提高代码库的可维护性和延展空间
- 减少沟通成本(直接用最佳实践)
- 开拓思维
7大原则
- 面对对象设计: 开闭原则,依赖倒置原则
- 开闭原则(The Open Closed Principle, OCP): 对扩展开放,对修改关闭。
- 依赖倒置(The Dependency Inversion Principle, DIP): 要依赖于抽象,不要依赖于具体。
- 拆分解构: 单一职责原则,接口隔离原则
- 单一职责(The Single Responsibility Principle, SRP)【对业务】: 让一个类只负责一件事。
- 接口隔离(The Interface Segregation Principle, ISP)【对架构】: 一个类对另一个类的依赖应该建立在最小的接口上。
- 类之间的通信: 合成复用原则,里氏替换原则,迪米特法则
- 合成复用: 尽量使用组合/聚合关系,少用继承。
- 里氏替换(The Liskov Substitution Principle, LSP): 任何基类可以出现的地方,子类一定可以出现。
- 迪米特法则/最少知识原则(Least Knowledge Principle, LKP): 一个对象对其他对象知道的越少越好,不和陌生人说话。
其他:
- 共同封闭原则: 一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
- 稳定抽象原则: 最稳定的包应该是最抽象的包,不稳定的包应该是具体的包,即包的抽象程度跟它的稳定性成正比。
- 稳定依赖原则: 包之间的依赖关系都应该是稳定方向依赖的,包要依赖的包要比自己更具有稳定性。
注意: 也有总结为S.O.L.I.D设计原则的: 单一责任原则, 开放封闭原则, 里氏替换原则, 接口分离原则, 依赖倒置原则
单一职责原则
定义: 一个类应该有且仅有一个引起它变化的原因
说明: 根据需求制定接口粒度,当这个类需要做过多事情的时候,就需要分解这个类。如果一个类承担的职责过多,就等于把这些职责耦合在了一起,一个职责的变化可能会削弱这个类完成其它职责的能力。
示例:
-
使用前:
public class BasicLaptop implements Laptop { String cpu = ""; int size = 0; public static void main(String args[]) { System.out.println("Hello"); } public void startUp() {}; public void shutDown() {}; } interface Laptop { String cpu = ""; int size = 0; void startUp(); void shutDown(); }
-
使用后:
public class MacBookV1 { private MacLaptopProperty property; private MacLaptopFunction function; public static void main(String[] args) { System.out.println("Hello"); } public MacBookV1(MacLaptopProperty p, MacLaptopFunction f) { this.property = p; this.function = f; } } interface LaptopProperty { String cpu = ""; int size = 0; String resolution = ""; } interface LaptopFunction { void startUp(); void shutDown(); } class MacLaptopProperty implements LaptopProperty { String cpu = ""; int size = 0; String resolution = ""; } class MacLaptopFunction implements LaptopFunction { public void startUp() {}; public void shutDown() {}; }
开闭原则
定义: 类应该对扩展开放,对修改关闭
说明: 在需求发生变化时,采取扩展组件的方式而不是删减代码。符合开闭原则最典型的设计模式是装饰者模式,它可以动态地将责任附加到对象上,而不用去修改类的代码。
好处: 测试简单、稳定性高
实现: 接口和抽象类
注意: 抽象层要保持稳定
示例:
-
使用前:
class EmailService: def send_notification(self, info): print(f'Email: {info}') class MessageService: def send_notification(self, info): print(f'Message: {info}') class NotificationService1: def send_notification(self, service_type, info): if service_type == 'email': self.send_email(info) elif service_type == 'message': self.send_message(info) def send_email(self, info): es = EmailService() es.send_notification(info) def send_message(self, info): ms = MessageService() ms.send_notification(info) ns = NotificationService1() ns.send_notification('email', 'hello') ns.send_notification('message', 'hello')
-
使用后:
class NotificationService: def send_notification(self, info): pass class EmailService(NotificationService): def send_notification(self, info): print(f'Email: {info}') class MessageService(NotificationService): def send_notification(self, info): print(f'Message: {info}') class WeChatService(NotificationService): def send_notification(self, info): print(f'WeChat: {info}') class NotificationService2: def send_notification(self, notification_service, info): notification_service.send_notification(info) ns = NotificationService2() ns.send_notification(EmailService(), 'hello') ns.send_notification(MessageService(), 'hello') ns.send_notification(WeChatService(), 'hello')
迪米特法则/最少知识原则
说明: 一个类对于其他类知道的越少越好(只与最直接的朋友通信)【不要存在objA.getObjB().doSomething()
】
好处: 降低耦合性,提高模块功能的独立性;非常实用
模式: 门面模式(Facade)、中介模式(Mediator)
注意: 可能会产生大量中间类
示例:
-
使用前:
class Card: balance = 10 class Customer: card = Card() def get_card(self): return self.card class SurfShop: def charge_customer(self, c: Customer, fee: float): c.get_card().balance -= fee customer = Customer() SurfShop().charge_customer(customer, 1.0)
-
使用后:
class Card: balance = 10 def deduct(self, fee: float): self.balance -= fee class Customer: card = Card() def pay(self, fee: float): self.card.deduct(fee) class SurfShop2: def charge_customer(self, c: Customer, fee: float): c.pay(fee) customer = Customer() SurfShop2().charge_customer(customer, 1.0)
依赖倒置原则
定义:
- 高层不应该依赖底层,两者应该基于抽象【抽象比细节稳定】
- 抽象不应该依赖细节,细节应该依赖抽象
说明: 高层模块包含一个应用程序中重要的策略选择和业务模块,如果高层模块依赖于低层模块,那么低层模块的改动就会直接影响到高层模块,从而迫使高层模块也需要改动。依赖于抽象意味着:
- 任何变量都不应该持有一个指向具体类的指针或者引用;
- 任何类都不应该从具体类派生;
- 任何方法都不应该覆写它的任何基类中的已经实现的方法。
好处: 结构更稳定,更好地应对需求变化
模式: 工厂方法(Factory Method)
示例:
-
使用前:
class BMW: def rent_bmw(self, model: str): print(f'BMW rented {model}') class Mercedes: def rent_mercedes(self, model: str): print(f'Mercedes rented {model}') class CarRentalAgency: def rent_car(self, brand: str, model: str): if brand == 'BMW': BMW().rent_bmw(model) elif brand == 'Mercedes': Mercedes().rent_mercedes(model) agency = CarRentalAgency() agency.rent_car('BMW', 'X5') agency.rent_car('Mercedes', 'GLE')
-
使用后:
class CarManufactory: def rent(self, model: str): pass class BMW(CarManufactory): def rent(self, model: str): print(f'BMW rented {model}') class Mercedes(CarManufactory): def rent(self, model: str): print(f'Mercedes rented {model}') class Honda(CarManufactory): def rent(self, model: str): print(f'Honda rented {model}') class CarRentalAgency2: def rent_car(self, manufactory: CarManufactory, model: str): manufactory.rent(model) agency = CarRentalAgency2() agency.rent_car(BMW(), 'X5') agency.rent_car(Mercedes(), 'GLE') agency.rent_car(Honda(), 'Accord')
合成复用原则
说明: 尽量使用对象聚合/组合,而不是继承关系达到软件复用的目的 【聚合/组合>继承】
- 继承复用(白箱复用):
- 优点: 简单、容易实现
- 缺点: 破坏了封装性、耦合高、限制灵活性
- 合成复用:
- 优点: 维持封装性、降低耦合度、灵活性高
- 缺点: 有较多的对象需要管理
示例:
-
使用前:
class GasolineCar: def move(self): print('gasoline move') class ElectricCar: def move(self): print('electric move') class RedGasolineCar(GasolineCar): def move(self): print('red gasoline move') class BlueGasolineCar(GasolineCar): def move(self): print('blue gasoline move') c = RedGasolineCar() c.move()
-
使用后:
class Car: enery = None color = None def __init__(self, energy, color): self.enery = energy self.color = color def move(self): print(f'{self.enery.__str__()} {self.color.__str__()}') class Energy: pass class Color: pass class Gasoline(Energy): def __str__(self): return 'gasoline' class Electric(Energy): def __str__(self): return 'electric' class Red(Color): def __str__(self): return 'red' class Blue(Color): def __str__(self): return 'blue' Car(Gasoline(), Red()).move() Car(Electric(), Blue()).move()
接口隔离原则
定义: 不应该强迫客户依赖于它们不用的方法。
说明: 使用多个专门的接口比使用单一的总接口要好。
- 客户端不应该依赖它不用等接口 => 低耦合
- 依赖不用的接口,会让接口变动的风险会加大
- 客户端不应被迫使用对其而言无用的方法或功能
- 类之间的依赖应该建立在最小的接口上面 => 高内聚
- 把庞大臃肿的接口拆分成更小和更具体的接口
- 最小接口: 满足项目需求的相似的功能
注意:
- 设计粒度太小范儿会适得其反
- 设计粒度参考,一个接口只服务于一个子模块或者业务逻辑
对比"单一职责原则":
- 约束偏向: 接口隔离偏向约束架构设计,单一职责偏向约束业务
- 细化程度: 单一职责更精细,接口隔离注重相似接口的隔离
示例:
-
使用前:
public class Game1 { public static void main(String[] args) { Monster m = new Monster(); m.basicAttack(); MonsterBoss b = new MonsterBoss(); b.magicAttack(); } } interface BadCharacterSkill { public void basicAttack(); public void magicAttack(); public void recover(); } class Monster implements BadCharacterSkill { public void basicAttack() { System.out.println("Monster basic attack"); } public void magicAttack() {}; public void recover() {}; } class MonsterBoss implements BadCharacterSkill { public void basicAttack() { System.out.println("Boss basic attack"); } public void magicAttack() { System.out.println("Boss magic attack"); } public void recover() { System.out.println("Boss recover"); }; }
-
使用后:
public class Game2 { public static void main(String[] args) { Monster m = new Monster(); m.basicAttack(); MonsterBoss b = new MonsterBoss(); b.magicAttack(); } } interface BasicBadCharacterSkill { public void basicAttack(); } interface AdvancedBadCharacterSkill { public void magicAttack(); public void recover(); } class Monster implements BasicBadCharacterSkill { public void basicAttack() { System.out.println("Monster basic attack"); } } class MonsterBoss implements BasicBadCharacterSkill, AdvancedBadCharacterSkill { public void basicAttack() { System.out.println("Boss basic attack"); } public void magicAttack() { System.out.println("Boss magic attack"); } public void recover() { System.out.println("Boss recover"); }; }
里氏替换原则
定义: 子类对象必须能够替换掉所有父类对象。
说明: 继承是一种IS-A关系,子类需要能够当成父类来使用,并且需要比父类更特殊。如果不满足这个原则,那么各个子类的行为上就会有很大差异,增加继承体系的复杂度。换句话说,任何基类出现的地方,子类一定可以出现。
理由:
- 继承关系给程序带来侵入性【父类修改子类可能也要改】
- 避免程序升级后的兼容性
- 避免程序出错
原则:
- 保证基类所拥有的性质在子类中依然成立
- 子类扩展父类的功能,但是不能改变父类原有的功能
规范:
- 子类必须完全实现父类的抽象方法【Java可以保证】,但不能覆盖父类的非抽象方法
- 子类可以实现自己特有的方法
- 当子类的方法实现父类的抽象方法时,方法的后置条件(方法的返回值)要比父类更严格【Java可以保证】
- 子类的实例可以替代父类的实例,但反之不成立
注意:
- 不遵守这一原则 => 当前代码没问题,未来出错率会提高
- 聚合/组合 > 继承(合成复用原则)
示例:
-
错误案例(规范1):
import abc class Calculator: @abc.abstractmethod def test(): raise NotImplementedError def calculate(self, n1, n2): return n1 + n2 class SuperCalculator(Calculator): def test(): print('super test') def calculate(self, n1, n2): # It's dangerous to overwrite non-abstract methods return n1 - n2 c = Calculator() print(c.calculate(1, 3)) sc = SuperCalculator() print(sc.calculate(1, 3))
-
错误案例(规范3):
import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main3 { public static ArrayList<String> stringToList(Calculator c, String s) { return c.stringToList(s); } } abstract class Calculator { public abstract ArrayList<String> stringToList(String s); } class SuperCalculator extends Calculator { public List<String> stringToList(String s) { // do something } }
23个设计模式
分为三大类: 行为型、结构型、创建型
创建型模式:
- 帮助我们创建类或者对象
- 核心思想: 把对象的创建和使用分离,使两者能相对独立地变换
- 相关设计模式
- 抽象工厂模式(Abstract Factory): 提供创建一系列相关或相互依赖对象的接口
- 生成器模式(Builder): 使用多个简单对象,构建成一个复杂对象
- 工厂方法模式(Factory Method): 父类中提供一个创建对象的共同接口,让子类决定实例化具体的对象
- 原型模式 (Prototype): 提供原型用于创建重复的对象
- 单例模式(Singleton): 保证一个类只有一个实例,仅提供一个访问它的全局访问点
结构性模式:
- 涉及如何组合各种对象以便获得更好、更灵活的结构
- 更多地通过组合与运行期的动态结合来实现更灵活的功能
- 相关设计模式
- 适配器模式(Adapter): 融合两个不兼容的类
- 桥接模式(Bridge): 将抽象与实现分离,使其可以独立变化
- 组合模式(Composite): 将对象组成树形结构,让单个对象和组合对象的使用具有一致性
- 装饰模式(Decorator): 动态给对象添加额外的职责
- 外观模式(Facade): 用一个统一接口来代理多个类的访问
- 享元模式(Flyweight): 使用对象池共享细粒度的对象,以減少内存占用
- 代理模式(Proxy): 提供代理以控制对特定对象的访问控制
行为型模式:
- 用于描述类或者对象是怎样交互和如何分配职责的。
- 涉及到算法和对象间的职责分配,描述一组对象应该如何协作来完成一个整体的任务。
- 相关设计模式
- 责任链模式(Chain of Responsibility): 将请求沿着链去处理,使多个对象都有机会处理请求
- 命令模式(Command): 将请求封装成命令,从而可用不同的请求对客户端进行参数化
- 解释器模式(Interpreter): 定义一个语言的语法,并提供解释器解释语言中的句子
- 迭代器模式(lterator): 提供一种方法顺序访问一个聚合对象中的各个元素,不暴露内部细节
- 中介者模式(Mediator): 用一个中介对象封装一系列的对象交互,实现多方的松耦合
- 备忘录模式(Memento): 保存对象的状态,在需要时进行恢复
- 观察者模式(Observer): 监听一个主对象,状态改变时,通知所有监听它的观察者
- 状态模式(Sate): 允许对象在内部状态改变时,同时改变它的行为
- 策略模式(Strategy): 封装不同的算法,让算法之间能互相替换
- 模板方法模式(Template Method): 定义算法框架,把待定的步骤留给子类实现
- 访问者模式(Visitor): 在稳定数据结构的前提下,定义新的操作行为
创建型模式
抽象工厂模式(abstract_factory)
场景: 提供统一的接口创建一系列相关的产品
- 不同厂商要生产不同款式的不同型号的车
- 游戏服装套装,通常一整套一起换
- 操作系统的组件模块,同一组模块需要对应相同的系统
思路:
说明:
- 提供一个创建一系列相关或者相互依赖对象的借口,而不制定他们具体的类
- 抽象工厂模式讲一组对象的实现细节与他们的一般使用分离开
代码:
from abc import ABC, abstractmethod
class Sedan(ABC):
@abstractmethod
def turn_on_head_light(self) -> None:
pass
class SUV(ABC):
@abstractmethod
def turn_on_head_light(self) -> None:
pass
class BMWM5(Sedan):
def turn_on_head_light(self) -> None:
print("BMWM5 head light")
class BMWX5(SUV):
def turn_on_head_light(self) -> None:
print("BMWX5 head light")
class TeslaModelS(Sedan):
def turn_on_head_light(self) -> None:
print("Tesla ModelS head light")
class TeslaModelY(SUV):
def turn_on_head_light(self) -> None:
print("Tesla ModelY head light")
class CarFactory(ABC):
@abstractmethod
def create_sedan(self) -> Sedan:
pass
@abstractmethod
def create_suv(self) -> SUV:
pass
class BMWFactory(CarFactory):
def create_sedan(self) -> Sedan:
return BMWM5()
def create_suv(self) -> SUV:
return BMWX5()
class TeslaFactory(CarFactory):
def create_sedan(self) -> Sedan:
return TeslaModelS()
def create_suv(self) -> SUV:
return TeslaModelY()
class BrandBooth:
sedan: Sedan = None
suv: SUV = None
def __init__(self, factory: CarFactory):
self.sedan = factory.create_sedan()
self.suv = factory.create_suv()
def show_time(self):
self.sedan.turn_on_head_light()
self.suv.turn_on_head_light()
if __name__ == '__main__':
bmw_factory = BMWFactory()
bmw_booth = BrandBooth(bmw_factory)
bmw_booth.show_time()
tesla_factory = TeslaFactory()
tesla_booth = BrandBooth(tesla_factory)
tesla_booth.show_time()
优缺点:
- 优点:
- 规范了创建相同系列产品的方式
- 只需要暴露创建接口,可以隐藏实现细节
- 容易改变产品的系列
- 缺点:
- 扩展产品库需要额外工作:除了产品代码外,还需要改动Factory
生成器模式(builder: 构建器)
场景: 逐步构建复杂的对象
- 定制汽车: 要生产不同功能组合的车
- 定制奶茶
思路:
说明: 1. Builder: 提供逐步创建产品的步骤 2. Director: 创建可复用的特定产品
类似的场景以及思路:
代码:
class Milktea {
double price;
String topping = "boba";
String tea = "regularMilktea";
Integer suger = 100;
public Milktea() {
this.price = 7.0;
}
public double getPrice() {
return this.price;
}
}
class SignatureMilktea extends Milktea {
public SignatureMilktea() {
this.price = 5.7;
}
}
class OolongMilktea extends Milktea {
public OolongMilktea() {
this.price = 4.5;
}
}
interface MilkteaBuilder {
void reset();
void addTopping();
void addTea();
void addSugerLevel();
Milktea getProduct();
}
class SignatureMilkteaBuilder implements MilkteaBuilder {
private SignatureMilktea product;
public void reset() {
this.product = new SignatureMilktea();
}
public void addTopping() {
product.topping = "boba";
}
public void addTea() {
product.tea = "signature tea";
}
public void addSugerLevel() {
product.suger = 100;
}
public Milktea getProduct() {
System.out.format("Signature milktea: %s %s %s\n", this.product.topping, this.product.tea, this.product.suger);
return this.product;
}
}
class OolongMilkteaBuilder implements MilkteaBuilder {
private OolongMilktea product;
public void reset() {
this.product = new OolongMilktea();
}
public void addTopping() {
product.topping = "grass jelly";
}
public void addTea() {
product.tea = "oolong";
}
public void addSugerLevel() {
product.suger = 50;
}
public Milktea getProduct() {
System.out.format("Oolong milktea: %s %s %s\n", this.product.topping, this.product.tea, this.product.suger);
return this.product;
}
}
class CustomizedMilkteaBuilder {
private Milktea product;
public void reset() {
this.product = new Milktea();
}
public void addTopping(String boba) {
product.topping = boba;
}
public void addTea(String tea) {
product.tea = tea;
}
public void addSugerLevel(Integer sugar) {
product.suger = sugar;
}
public Milktea getProduct() {
System.out.format("Customized milktea: %s %s %s\n", this.product.topping, this.product.tea, this.product.suger);
return this.product;
}
}
class MilkteaDirector {
private MilkteaBuilder milkteaBuilder;
public MilkteaDirector(MilkteaBuilder builder) {
this.milkteaBuilder = builder;
}
public void changeBuilder(MilkteaBuilder builder) {
this.milkteaBuilder = builder;
}
public Milktea makeMiketea() {
this.milkteaBuilder.reset();
this.milkteaBuilder.addTopping();;
this.milkteaBuilder.addTea();
this.milkteaBuilder.addSugerLevel();
return this.milkteaBuilder.getProduct();
}
public Milktea make(String type) {
if (type == "signature") {
this.changeBuilder(new SignatureMilkteaBuilder());
} else if (type == "oolong") {
this.changeBuilder(new OolongMilkteaBuilder());
}
return this.makeMiketea();
}
}
public class TuringBobaShop {
public static void main(String[] args) {
MilkteaDirector director = new MilkteaDirector(new SignatureMilkteaBuilder());
director.makeMiketea();
director.changeBuilder(new OolongMilkteaBuilder());
director.makeMiketea();
director.make("signature");
director.make("oolong");
CustomizedMilkteaBuilder builder = new CustomizedMilkteaBuilder();
builder.reset();
builder.addTopping("boba");
builder.addTea("Oolong");
builder.addSugerLevel(10);
builder.getProduct();
}
}
优缺点:
- 优点
- 分步创建,更加灵活
- 可以复用相同的制作代码
- 严格遵循单一职责原则
- 缺点
- 代码整体复杂度增加
对比"抽象工厂":
生成器 | 抽象工厂 | |
---|---|---|
目的 | 构建复杂对象 | 创建一系列相关联的对象 |
创建对象方式 | 多步骤创建 | 单一步骤创建 |
工厂方法模式(factory_method)
场景: 将产品的实例化延迟到具体工厂中完成
- 创建对象需要使用大量重复代码
- 无需客户端知道具体产品的类别和依赖关系,只需要知道对应工厂就好
代码:
from abc import ABC, abstractmethod
class Car(ABC):
@abstractmethod
def startEngine(self):
pass
@abstractmethod
def turnOffEngine(self):
pass
class ModelA(Car):
def startEngine(self):
print("modelA startEngine")
return True
def turnOffEngine(self):
print("modelA turnOffEngine")
class ModelB(Car):
def startEngine(self):
print("modelB startEngine")
return True
def turnOffEngine(self):
print("modelB turnOffEngine")
class CarFactory(ABC):
@abstractmethod
def makeCar(self):
pass
class ModelAFactory(CarFactory):
def makeCar(self):
modelA = ModelA()
if modelA.startEngine() == True:
modelA.turnOffEngine()
return modelA
else:
return None
class ModelBFactory(CarFactory):
def makeCar(self):
modelB = ModelB()
if modelB.startEngine() == True:
modelB.turnOffEngine()
return modelB
else:
return None
class TuringStorage:
carStorage = [None] * 10
def importCars(self):
factoryA = ModelAFactory()
factoryB = ModelBFactory()
for i in range(5):
self.carStorage[i] = factoryA.makeCar()
for i in range(5, 10):
self.carStorage[i] = factoryB.makeCar()
storage = TuringStorage()
storage.importCars()
优缺点:
- 优点: 降低耦合性、保持了封装性
- 缺点: 每增加一个产品就要添加工厂类,增加系统的复杂度
工厂对比:
简单工厂 | 工厂方法 | 抽象工厂 | |
---|---|---|---|
模式特点 | 一个工厂创建所有产品 | 每个产品对应具体的工厂 | 具体工厂创建多个具体产品 |
应用场景 | 产品线少,解耦客户端和具体产品 | 产品线较多 | 创建一系列相关的产品 |
原型模式(prototype)
场景: 复制对象
- 需要使用大量的复制
- 复制复杂的数据结构
原型模式:
1. 由于要复制的产品中可能有很多(私有)属性,所以需要在对象内部完成复制
2. 在产品内部实现clone
方法(由interface Prototype
规范),需要复制时,在工厂对象中调用clonePrototpype
代码:
import java.util.HashMap;
public class TennisPlayer {
public static void main(String[] args) {
TennisRacketPrototypeManager.buildProtypes();
for (int i = 0; i < 10; i++) {
TennisRacketPrototypeManager.getClonedRacket("pro staff");
}
}
}
abstract class RacketPrototype {
protected String brand;
protected String model;
protected double weight;
protected double balancePoint;
public RacketPrototype(String brand, String model, double weight, double balancePoint) {
this.brand = brand;
this.model = model;
this.weight = weight;
this.balancePoint = balancePoint;
}
public abstract RacketPrototype clone();
}
class WilsonTennisRacket extends RacketPrototype {
public WilsonTennisRacket(String brand, String model, double weight, double balancePoint) {
super(brand, model, weight, balancePoint);
}
@Override
public RacketPrototype clone() {
System.out.printf("Wilson clone: %s %s %s %s\n", this.brand, this.model, this.weight, this.balancePoint);
return new WilsonTennisRacket(this.brand, this.model, this.weight, this.balancePoint);
}
}
class HeadTennisRacket extends RacketPrototype {
public HeadTennisRacket(String brand, String model, double weight, double balancePoint) {
super(brand, model, weight, balancePoint);
}
@Override
public RacketPrototype clone() {
System.out.printf("Head clone: %s %s %s %s\n", this.brand, this.model, this.weight, this.balancePoint);
return new HeadTennisRacket(this.brand, this.model, this.weight, this.balancePoint);
}
}
class TennisRacketPrototypeManager {
private static HashMap<String, RacketPrototype> racketMap = new HashMap<String, RacketPrototype>();
public static RacketPrototype getClonedRacket(String model) {
RacketPrototype r = racketMap.get(model);
return (RacketPrototype) r.clone();
}
public static void buildProtypes() {
WilsonTennisRacket r1 = new WilsonTennisRacket("Wilson", "Pro Staff", 320.0, 32.5);
racketMap.put("pro staff", r1);
HeadTennisRacket h1 = new HeadTennisRacket("Head", "Graphene 360 Speed", 320.0, 32.5);
racketMap.put("graphene 360", h1);
}
}
优缺点:
- 优点
- 提高代码的可复用性
- 增加系统的灵活度
- 减少复制的时间和资源
- 缺点
- 增加复杂度
- 原型复制的不一致
- 内存使用可能会被提高
单例模式(singleton)
场景:
- 资源分享: 数据库
- 配置管理
- 缓存
- 日志管理
- 对象工厂
- 线程池本身的创建【固定线程池的创建可以看作"多例模式"】
作用:
- 保证一个类只有一个实例
- 为该实例提供了一个全局唯一的访问节点(
getInstance
)
代码:
- 饿汉式
class King { private static King king = new King(); private King(){ } public static King getInstance(){ return king; } }
- 懒汉式【要注意多线程场景(
getInstance()
上加synchronized
)】class Worker: def __init__(self, name): self.name = name def serve_customer(self): print(self.name + " is serving customer") class CustomerServiceCenter: __instance = None @staticmethod def get_instance(): if CustomerServiceCenter.__instance is None: CustomerServiceCenter() return CustomerServiceCenter.__instance def __init__(self): if CustomerServiceCenter.__instance is not None: raise Exception("Singleton object cannot be initialized more than once") else: CustomerServiceCenter.__instance = self self.holiday = False self.holiday_workers = [ Worker("holiday worker 1"), Worker("holiday worker 2"), Worker("holiday worker 3") ] self.non_holiday_workers = [ Worker("non-holiday worker 1"), Worker("non-holiday worker 2"), Worker("non-holiday worker 3") ] def set_holiday(self, holiday): self.holiday = holiday def serve_customer(self): if self.holiday: # Service by holiday workers for worker in self.holiday_workers: worker.serve_customer() else: # Service by non-holiday workers for worker in self.non_holiday_workers: worker.serve_customer() # Use the singleton object to serve customers service1 = CustomerServiceCenter.get_instance() service1.serve_customer() service2 = CustomerServiceCenter.get_instance() service2.serve_customer() service2.set_holiday(True) service1.serve_customer() service2.serve_customer()
优缺点:
- 优点
- 提高调用速度
- 更有效利用资源
- 防止资源冲突和一致性问题
- 缺点
- 潜在的竞争条件(race conditions)和线程安全(thread-safety)问题
- 对于不频繁创建和销毁的对象只会增加系统开支,因为它一直存在,但是对于频繁创建和销毁的却可以在一定程度上减少开支
结构性模式
适配器模式(adapter)
作用: 让接口不兼容的对象能够合作
场景: e.g. 文件输出跟输入的格式不一样,需要中间件来转换
- 基本应用: 支持多接口,重用现有的代码
- 连接遗留代码和新系统
- 连接第三方库
- 单元测试: 模拟真正对象的行为(Mock objects)
角色:
- 请求者Client: 调用服务的角色
- 目标Target: 定义了Client要使用的功能
- 转换对象Adaptee: 需要被适配器转换的对象
- 适配器Adapter: 实现转换功能的对象
实现方法:
-
类适配器模式,用继承
class CelsiusTemperature: def getCTemperature(self): pass class FahrenheitTemperature: def __init__(self, temperature): self.temperature = temperature def getTemperature(self): return self.temperature class FahrenheitToCelsiusAdapter(FahrenheitTemperature, CelsiusTemperature): def __init__(self, temperature): super().__init__(temperature) def getCTemperature(self): return (super().getTemperature() - 32) * 5 / 9 f = FahrenheitTemperature(100) c = FahrenheitToCelsiusAdapter(f.getTemperature()) print("The temperature is", c.getCTemperature(), "degrees Celsius.")
-
对象适配器模式,用组合
# The target interface class CelsiusTemperature: def getCTemperature(self): pass # The existing class that needs to be adapted class FahrenheitTemperature: def __init__(self, temperature): self.temperature = temperature def getTemperature(self): return self.temperature # The adapter class that adapts FahrenheitTemperature to CelsiusTemperature class FahrenheitToCelsiusAdapter(CelsiusTemperature): def __init__(self, fahrenheit): self.fahrenheit = fahrenheit def getCTemperature(self): # Convert Fahrenheit to Celsius and return the temperature return (self.fahrenheit.getTemperature() - 32) * 5 / 9 # Client code that uses the adapter if __name__ == '__main__': # Create a FahrenheitTemperature object with some value f = FahrenheitTemperature(100) # Create a FahrenheitToCelsiusAdapter object with the FahrenheitTemperature object as input c = FahrenheitToCelsiusAdapter(f) # Use the adapter to get the temperature in Celsius print("The temperature is", c.getCTemperature(), "degrees Celsius.")
-
双向适配器
# The Celsius interface class CelsiusTemperature: def get_temperature(self): pass # The Fahrenheit interface class FahrenheitTemperature: def get_temperature(self): pass # The Celsius class that implements CelsiusTemperature class Celsius(CelsiusTemperature): def __init__(self, temperature): self.temperature = temperature def get_temperature(self): return self.temperature # The Fahrenheit class that implements FahrenheitTemperature class Fahrenheit(FahrenheitTemperature): def __init__(self, temperature): self.temperature = temperature def get_temperature(self): return self.temperature # The two-way adapter that implements both CelsiusTemperaure and FahrenheitTemperaure class TwoWayAdapter(CelsiusTemperature, FahrenheitTemperature): def __init__(self, celsius=None, fahrenheit=None): if celsius: self.celsius = celsius self.fahrenheit = Fahrenheit(celsius.get_temperature() * 9 / 5 + 32) else: self.fahrenheit = fahrenheit self.celsius = Celsius((fahrenheit.get_temperature() - 32) * 5 / 9) # Delegate calls to celsius or fahrenheit or provide conversion functionality def get_celsius_temperature(self): return self.celsius.get_temperature() def get_fahrenheit_temperature(self): return self.fahrenheit.get_temperature() celsius = Celsius(25) fahrenheit = Fahrenheit(77) adapter1 = TwoWayAdapter(celsius) adapter2 = TwoWayAdapter(fahrenheit) print("Celsius temperature:", adapter1.get_celsius_temperature()) print("Fahrenheit temperature:", adapter1.get_fahrenheit_temperature()) print("Celsius temperature:", adapter2.get_celsius_temperature()) print("Fahrenheit temperature:", adapter2.get_fahrenheit_temperature())
优缺点:
- 优点
- 把转换代码从业务逻辑中分离出来
- 在不修改现有代码的情况下实现转化
- 让代码更加模块化而且可以复用
- 缺点
- 代码的整体复杂度会增加
- 重复代码
- 很难Debug
桥接模式(bridge)
作用: 把抽象与实现分离开
举例: 电商产品与付款
-
使用前
class Book: def purchaseWithCreditCard(self, creditCard): creditCard.processPayment() print("Purchased book") def purchaseWithWeChat(self, payPalAccount): payPalAccount.processPayment() print("Purchased book") class Electronics: def purchaseWithCreditCard(self, creditCard): creditCard.processPayment() print("Purchased electronics") def purchaseWithWeChat(self, payPalAccount): payPalAccount.processPayment() print("Purchased electronics") class CreditCardPayment: def processPayment(self): print("Processing credit card payment") class WeChatPayment: def processPayment(self): print("Processing wechat payment") if __name__ == "__main__": book = Book() electronics = Electronics() creditCardPayment = CreditCardPayment() wechatPayment = WeChatPayment() book.purchaseWithCreditCard(creditCardPayment) electronics.purchaseWithCreditCard(creditCardPayment) book.purchaseWithWeChat(wechatPayment) electronics.purchaseWithWeChat(wechatPayment)
-
使用后
from abc import ABC, abstractmethod class Payment(ABC): @abstractmethod def processPayment(self): pass class CreditCardPayment(Payment): def processPayment(self): print("Processing credit card payment") class WeChatPayment(Payment): def processPayment(self): print("Processing wechat payment") class Product(ABC): def __init__(self, payment: Payment): self.payment = payment @abstractmethod def purchase(self): pass class Book(Product): def __init__(self, payment: Payment): super().__init__(payment) def purchase(self): self.payment.processPayment() print("Purchased book") class Electronics(Product): def __init__(self, payment: Payment): super().__init__(payment) def purchase(self): self.payment.processPayment() print("Purchased electronics") if __name__ == "__main__": creditCardPayment = CreditCardPayment() wechatPayment = WeChatPayment() book = Book(creditCardPayment) book.purchase() electronics = Electronics(creditCardPayment) electronics.purchase() book2 = Book(wechatPayment) book2.purchase()
举例: 电视与遥控器
abstract class RemoteControl {
protected Device device;
public RemoteControl(Device device) {
this.device = device;
}
public abstract void powerOn();
public abstract void powerOff();
public abstract void volumeUp();
public abstract void volumeDown();
}
interface Device {
void powerOn();
void powerOff();
void setVolume(int volume);
int getVolume();
}
class TV implements Device {
private int volume = 50;
@Override
public void powerOn() {
System.out.println("TV is on.");
}
@Override
public void powerOff() {
System.out.println("TV is off.");
}
@Override
public void setVolume(int volume) {
if (volume > 100) {
this.volume = 100;
} else if (volume < 0) {
this.volume = 0;
} else {
this.volume = volume;
}
System.out.println("TV volume set to " + this.volume);
}
@Override
public int getVolume() {
return volume;
}
}
class DVDPlayer implements Device {
private int volume = 50;
@Override
public void powerOn() {
System.out.println("DVD player is on.");
}
@Override
public void powerOff() {
System.out.println("DVD player is off.");
}
@Override
public void setVolume(int volume) {
if (volume > 100) {
this.volume = 100;
} else if (volume < 0) {
this.volume = 0;
} else {
this.volume = volume;
}
System.out.println("DVD player volume set to " + this.volume);
}
@Override
public int getVolume() {
return volume;
}
}
class BasicRemote extends RemoteControl {
public BasicRemote(Device device) {
super(device);
}
@Override
public void powerOn() {
System.out.print("Basic Remote: power on -> ");
device.powerOn();
}
@Override
public void powerOff() {
System.out.print("Basic Remote: power off -> ");
device.powerOff();
}
@Override
public void volumeUp() {
device.setVolume(device.getVolume() + 10);
}
@Override
public void volumeDown() {
device.setVolume(device.getVolume() - 10);
}
}
class AdvancedRemote extends RemoteControl {
public AdvancedRemote(Device device) {
super(device);
}
@Override
public void powerOn() {
System.out.print("Advanced Remote: power on -> ");
device.powerOn();
}
@Override
public void powerOff() {
System.out.print("Advanced Remote: power off -> ");
device.powerOff();
}
@Override
public void volumeUp() {
device.setVolume(device.getVolume() + 5);
}
@Override
public void volumeDown() {
device.setVolume(device.getVolume() - 5);
}
}
public class RemoteTV {
public static void main(String[] args) {
Device tv = new TV();
Device dvdPlayer = new DVDPlayer();
RemoteControl basicRemote = new BasicRemote(tv);
basicRemote.powerOn();
basicRemote.powerOff();
basicRemote.volumeUp();
basicRemote.volumeDown();
RemoteControl advancedRemote = new AdvancedRemote(dvdPlayer);
advancedRemote.powerOn();
advancedRemote.powerOff();
advancedRemote.volumeUp();
advancedRemote.volumeDown();
basicRemote = new BasicRemote(dvdPlayer);
basicRemote.powerOn();
basicRemote.powerOff();
basicRemote.volumeUp();
basicRemote.volumeDown();
}
}
优缺点:
- 优点
- 让抽离和实现独立
- 灵活和可拓展的架构
- 增加代码复用,可读性和可维护性
- 简化测试和调试
- 缺点
- 增加复杂度
- 更多规划和设计工作
- 不必要的抽象和冗余代码
- 可读性降低
应用场景
- 隐藏实现细节
- 避免抽象和实现的绑定
- 提高代码可拓展性
- 应用案例:GUI框架,绘图程序,数据库驱动系统
和适配器模式区别
- 适配器模式是将两个不兼容的接口连起来(针对已有代码)
- 桥接模式是前期设计时分离抽象与实现
组合模式(composite)
举例: 部门组织架构的调整
- 使用前:
class Employee: def __init__(self, name): self.name = name def print_name(self): print(self.name) class Department: def __init__(self, name, employees=[]): self.name = name self.employees = employees class Team: def __init__(self, name, departments=[]): self.name = name self.departments = departments class Manager: def __init__(self, name, teams=[]): self.name = name self.teams = teams def print_manager_names(manager): print("Manager:", manager.name) for team in manager.teams: print_team_names(team) def print_team_names(team): print("Team:", team.name) for department in team.departments: print_department_names(department) def print_department_names(department): print("Department:", department.name) for employee in department.employees: employee.print_name() employees = [Employee("John"), Employee("Jane"), Employee("Bob")] department = Department("Engineering", employees) team = Team("Product", [department]) manager = Manager("Alice", [team]) print_manager_names(manager)
- 使用后:
from abc import ABC, abstractmethod class Component(ABC): @abstractmethod def print_name(self): pass class Employee(Component): def __init__(self, name): self.name = name def print_name(self): print(self.name) class Department(Component): def __init__(self, name, components=[]): self.name = name self.components = components def print_name(self): print("Department:", self.name) for component in self.components: component.print_name() class Team(Component): def __init__(self, name, components=[]): self.name = name self.components = components def print_name(self): print("Team:", self.name) for component in self.components: component.print_name() class Manager(Component): def __init__(self, name, components=[]): self.name = name self.components = components def print_name(self): print("Manager:", self.name) for component in self.components: component.print_name() employees = [Employee("John"), Employee("Jane"), Employee("Bob")] department = Department("Engineering", employees) team = Team("Product", [department]) manager = Manager("Alice", [team]) manager.print_name()
特点:
- 递归组合
- 树状结构
- 统一处理处理所有对象
优缺点:
-
优点
- 简化客户端操作
- 易于扩展
-
缺点
- 可能违反开闭原则
应用场景:
- 层次结构系统
- 对单个对象和组合对象进行相同操作
注意事项:
- 确保组件接口适合叶子节点和组合对象
- 把可选方法放入具体的叶子节点
装饰模式(decorator)
特点:
- 灵活拓展新功能
- 动态添加额外职责
举例: 公司通知发送
// Notifier interface
interface Notifier {
void send(String message);
}
// Concrete Component
class EmailNotifier implements Notifier {
@Override
public void send(String message) {
System.out.println("Sending Email message: " + message);
}
}
// Decorator abstract class
abstract class NotifierDecorator implements Notifier {
protected Notifier notifier;
public NotifierDecorator(Notifier notifier) {
this.notifier = notifier;
}
@Override
public void send(String message) {
notifier.send(message);
}
}
// Concrete Decorator classes
class WeChatDecorator extends NotifierDecorator {
public WeChatDecorator(Notifier notifier) {
super(notifier);
}
@Override
public void send(String message) {
super.send(message);
System.out.println("Sending WeChat message: " + message);
}
}
class MobileDecorator extends NotifierDecorator {
public MobileDecorator(Notifier notifier) {
super(notifier);
}
@Override
public void send(String message) {
super.send(message);
System.out.println("Sending Mobile message: " + message);
}
}
// Client
public class CompanyNotification {
public static void main(String[] args) {
String message = "Hello, this is a notification!";
// Sending notifications using different combinations
Notifier notifier = new EmailNotifier();
notifier = new WeChatDecorator(notifier);
notifier = new MobileDecorator(notifier);
notifier.send(message);
}
}
说明:
- 其实python中有直接实现类似结构的装饰器
优缺点:
- 优点
- 提高灵活性和可扩展性
- 简便不同的组合
- 提高可维护性
- 缺点
- 代码的复杂性
- 增加性能开销
应用场景:
- 在不影响其他对象的情况下,为单个对象添加新功能
- 动态组合多种可选功能
- 具体应用: GU可视化组件,通信协议,日志系统,权限控制系统,字符输入缓冲流(
BufferedReader
)
相似模式对比:
模式 | 目的 | 模式架构主要角色 | 应用场景 |
---|---|---|---|
生成器模式 | 分布构建复杂对象 | 指挥者、生成器 | 构建具有复杂逻辑的对象 |
组合模式 | 表示具有层次结构的对象 | 组合类和叶子节点 | 树形结构与递归结构 |
装饰器模式 | 动态添加新功能 | 抽象组件和装饰器 | 功能组合和扩展 |
外观模式(facade)
目的: 简化和复杂系统的交互方式
特点: 提供一个统一的交互接口
案例: 客服中心
class Payment {
private double amount;
public Payment(double amount) {
this.amount = amount;
}
public double getAmount() {
return amount;
}
}
enum RefundStatus {
SUCCESS, FAILURE
}
class Billing {
public Payment getPaymentForOrder(int orderId) {
// Simple Implementation
return new Payment(50.0);
}
public RefundStatus processRefund(Payment payment) {
// Simple Implementation
if (payment.getAmount() > 0) {
return RefundStatus.SUCCESS;
} else {
return RefundStatus.FAILURE;
}
}
}
class Shipping {
public void updateShippingAddress(int orderId, String newAddress) {
System.out.println("Shipping address for order " + orderId + " updated to: " + newAddress);
}
}
class Issue {
private String description;
public Issue(String description) {
this.description = description;
}
public String getDescription() {
return description;
}
}
class CustomerService {
public void notifyCustomer(String message) {
System.out.println("Notification sent to customer: " + message);
}
public void escalateToManager(Issue issue) {
System.out.println("Issue escalated to manager: " + issue.getDescription());
}
}
class CustomerSupportFacade {
private Billing billing;
private Shipping shipping;
private CustomerService customerService;
public CustomerSupportFacade(Billing billing, Shipping shipping, CustomerService customerService) {
this.billing = billing;
this.shipping = shipping;
this.customerService = customerService;
}
public void handleRefundRequest(int orderId) {
Payment payment = billing.getPaymentForOrder(orderId);
RefundStatus refundStatus = billing.processRefund(payment);
customerService.notifyCustomer("Refund status: " + refundStatus);
}
public void changeShippingAddress(int orderId, String newAddress) {
shipping.updateShippingAddress(orderId, newAddress);
customerService.notifyCustomer("Shipping address updated");
}
public void escalateToManager(Issue issue) {
customerService.escalateToManager(issue);
}
}
public class CustomerSuportClient {
public static void main(String[] args) {
Billing billing = new Billing();
Shipping shipping = new Shipping();
CustomerService customerService = new CustomerService();
CustomerSupportFacade customerSupport = new CustomerSupportFacade(billing, shipping, customerService);
customerSupport.handleRefundRequest(12345);
customerSupport.changeShippingAddress(12345, "123 New Street, New York, NY 10001");
Issue issue = new Issue("Product not working properly");
customerSupport.escalateToManager(issue);
}
}
优缺点:
- 优点
- 简化交互方式
- 解耦合
- 提高可维护性
- 缺点
- 不符合开闭原则
- 隐藏了潜在问题
应用场景:
- 子系统接口复杂
- 需要将子系统划分为多个层次
- 解耦客户端与子系统
- 具体应用: 复杂的library,跨平台的程序,电商系统
享元模式(flyweight)
from typing import Dict
from abc import ABC, abstractmethod
class Shape(ABC):
@abstractmethod
def draw(self, x: int, y: int, radius: int):
pass
class CircleFlyweight(Shape):
def __init__(self, color: str):
self.color = color
def draw(self, x: int, y: int, radius: int):
print(f'Drawing circle of color {self.color} at position ({x}, {y}) with radius {radius}')
class ShapeFactory:
_circle_map: Dict[str, CircleFlyweight] = {}
@staticmethod
def get_circle(color: str) -> CircleFlyweight:
circle = ShapeFactory._circle_map.get(color)
if circle is None:
circle = CircleFlyweight(color)
ShapeFactory._circle_map[color] = circle
print(f'Creating circle of color: {color}')
return circle
class DrawingApp2:
@staticmethod
def main():
red_circle = ShapeFactory.get_circle("red")
red_circle.draw(10, 10, 50)
blue_circle = ShapeFactory.get_circle("blue")
blue_circle.draw(20, 20, 60)
another_red_circle = ShapeFactory.get_circle("red")
another_red_circle.draw(30, 30, 40)
if __name__ == "__main__":
DrawingApp2.main()
目的: 最小化内存的使用
特点:
- 共享相似实例
- 把实例的共享状态和不共享状态分开
案例: 士兵游戏
import java.util.HashMap;
import java.util.Map;
// Flyweight interface
interface SoldierFlyweight {
void display(int x, int y);
}
// Concrete Flyweight class
class SoldierType implements SoldierFlyweight {
private String type;
private String weapon;
private String armor;
public SoldierType(String type, String weapon, String armor) {
this.type = type;
this.weapon = weapon;
this.armor = armor;
}
@Override
public void display(int x, int y) {
System.out.println("Displaying " + type + " at (" + x + ", " + y + ") with weapon " + weapon + " and armor " + armor);
}
}
class SoldierFlyweightFactory {
private Map<String, SoldierFlyweight> soldierTypeMap = new HashMap<>();
public SoldierFlyweight getSoldierType(String type, String weapon, String armor) {
SoldierFlyweight soldierType = soldierTypeMap.get(type);
if (soldierType == null) {
soldierType = new SoldierType(type, weapon, armor);
soldierTypeMap.put(type, soldierType);
}
return soldierType;
}
}
class Soldier {
private SoldierFlyweight soldierFlyweight;
private int x;
private int y;
public Soldier(SoldierFlyweight soldierFlyweight, int x, int y) {
this.soldierFlyweight = soldierFlyweight;
this.x = x;
this.y = y;
}
public void display() {
soldierFlyweight.display(x, y);
}
}
// Client
public class SoilderGame {
public static void main(String[] args) {
SoldierFlyweightFactory soldierTypeFactory = new SoldierFlyweightFactory();
// Create soldier types using the factory
SoldierFlyweight archerType = soldierTypeFactory.getSoldierType("Archer", "Bow", "Leather");
SoldierFlyweight knightType = soldierTypeFactory.getSoldierType("Knight", "Sword", "Plate");
// Create soldiers of different types
Soldier archer1 = new Soldier(archerType, 100, 50);
Soldier archer2 = new Soldier(archerType, 120, 60);
Soldier knight1 = new Soldier(knightType, 200, 100);
Soldier knight2 = new Soldier(knightType, 250, 120);
// Display soldiers
archer1.display();
archer2.display();
knight1.display();
knight2.display();
}
}
优缺点:
- 优点
- 减少内存使用
- 提高性能
- 可扩展性
- 缺点
- 复杂度: 内外部状态,享元工厂
- 多线程环境困难
- 适用性有限
- 应用场景: 需要大量共享数据
- 文字编辑器和处理器
- 图形应用
- 游戏开发
- Java的包装类型
(静态)代理模式(proxy)
举例: 图片加载与展示(这就类似在线数据集的加载)
class RemoteImage:
def __init__(self, url):
self.url = url
def display_image(self):
print("Displaying image from URL:", self.url)
# Code to load and display the image
class ImageProxy:
def __init__(self, url):
self.url = url
self.image = None
def display_image(self):
if self.image is None:
print("New image from URL:", self.url)
self.image = RemoteImage(self.url)
self.image.display_image()
def main():
image_proxy = ImageProxy("http://example.com/image.jpg")
image_proxy.display_image() # Image is loaded from the server
image_proxy.display_image() # Image is loaded from the cache
if __name__ == "__main__":
main()
特点:
- 让一个对象控制对另一个对象的访问
- 让代理充当其他事物的接口
不同类型代理: 1. 虚拟代理: 当对象初始化时,需要消耗大量资源,该代理用于推迟对象初始化 2. 缓存代理: 缓存对象操作结果,避免重复计算或请求 3. 保护代理: 根据用户的访问权限,控制访问 4. 远程代理 5. 智能引用代理
举例: 银行账户管理
interface BankAccount {
void deposit(double amount);
void withdraw(double amount);
}
class RealBankAccount implements BankAccount {
private double balance;
public RealBankAccount(double initialBalance) {
this.balance = initialBalance;
}
@Override
public void deposit(double amount) {
balance += amount;
System.out.println("Deposited: " + amount + ", new balance: " + balance);
}
@Override
public void withdraw(double amount) {
if (balance >= amount) {
balance -= amount;
System.out.println("Withdrew: " + amount + ", new balance: " + balance);
} else {
System.out.println("Insufficient balance");
}
}
}
class BankAccountProxy implements BankAccount {
private RealBankAccount realBankAccount;
private String userRole;
public BankAccountProxy(String userRole, double initialBalance) {
this.userRole = userRole;
this.realBankAccount = new RealBankAccount(initialBalance);
}
@Override
public void deposit(double amount) {
if (userRole.equals("Admin") || userRole.equals("User")) {
realBankAccount.deposit(amount);
} else {
System.out.println("Unauthorized access");
}
}
@Override
public void withdraw(double amount) {
if (userRole.equals("Admin")) {
realBankAccount.withdraw(amount);
} else {
System.out.println("Unauthorized access");
}
}
}
public class BankAccountProxyMain {
public static void main(String[] args) {
BankAccount adminAccount = new BankAccountProxy("Admin", 1000);
adminAccount.deposit(500);
adminAccount.withdraw(200);
BankAccount userAccount = new BankAccountProxy("User", 1000);
userAccount.deposit(500);
userAccount.withdraw(200); // Will print "Unauthorized access"
}
}
优缺点:
- 优点:
- 关注点分离
- 访问控制
- 延迟实例化
- 远程访问
- 缓存
- 额外的行为
- 缺点:
- 增加复杂性
- 间接性
- 性能开销
应用场景和应用:
- 访问控制
- 缓存
- 保护代理
- 远程对象
- 智能引用
- 其他: 日志记录、监控和审计
行为型模式
责任链模式(chain_of_responsibility)
案例: 日志系统
- 使用前
class Logger { public static final int ERROR = 1; public static final int DEBUG = 2; public static final int INFO = 3; private int level; public Logger(int level) { this.level = level; } public void logMessage(int logLevel, String message) { if (logLevel == ERROR && logLevel <= level) { System.out.println("Error: " + message); } else if (logLevel == DEBUG && logLevel <= level) { System.out.println("Debug: " + message); } else if (logLevel == INFO && logLevel <= level) { System.out.println("Info: " + message); } } } public class LoggerDemo1 { public static void main(String[] args) { Logger logger = new Logger(Logger.INFO); logger.logMessage(Logger.ERROR, "This is an error message"); logger.logMessage(Logger.DEBUG, "This is a debug message"); logger.logMessage(Logger.INFO, "This is an info message"); } }
- 使用后
abstract class Logger { protected int level; protected Logger nextLogger; public void setNextLogger(Logger nextLogger) { this.nextLogger = nextLogger; } public void logMessage(int logLevel, String message) { if (logLevel <= level) { write(message); } else if (nextLogger != null) { nextLogger.logMessage(logLevel, message); } } abstract protected void write(String message); } class ErrorLogger extends Logger { public ErrorLogger(int level) { this.level = level; } @Override protected void write(String message) { System.out.println("Error: " + message); } } class DebugLogger extends Logger { public DebugLogger(int level) { this.level = level; } @Override protected void write(String message) { System.out.println("Debug: " + message); } } class InfoLogger extends Logger { public InfoLogger(int level) { this.level = level; } @Override protected void write(String message) { System.out.println("Info: " + message); } } public class LoggerDemo2 { public static void main(String[] args) { ErrorLogger errorLogger = new ErrorLogger(1); DebugLogger debugLogger = new DebugLogger(2); InfoLogger infoLogger = new InfoLogger(3); errorLogger.setNextLogger(debugLogger); debugLogger.setNextLogger(infoLogger); errorLogger.logMessage(1, "This is an error message"); errorLogger.logMessage(2, "This is a debug message"); errorLogger.logMessage(3, "This is an info message"); } }
特点: 允许多个对象按顺序处理请求或任务
主要组件:
- 处理器接口(handler)
- 具体处理器(concreteHandler)
举例: 自动取款机
from abc import ABC, abstractmethod
class DispenseChain(ABC):
@abstractmethod
def set_next_chain(self, next_chain):
pass
@abstractmethod
def dispense(self, currency):
pass
class Currency:
def __init__(self, amount):
self.amount = amount
def get_amount(self):
return self.amount
class Dollar50Dispenser(DispenseChain):
def __init__(self):
self.chain = None
def set_next_chain(self, next_chain):
self.chain = next_chain
def dispense(self, currency):
if currency.get_amount() >= 50:
number_of_notes = currency.get_amount() // 50
remainder = currency.get_amount() % 50
print(f"Dispensing {number_of_notes} 50$ note")
if remainder != 0:
self.chain.dispense(Currency(remainder))
else:
self.chain.dispense(currency)
class Dollar20Dispenser(DispenseChain):
def __init__(self):
self.chain = None
def set_next_chain(self, next_chain):
self.chain = next_chain
def dispense(self, currency):
if currency.get_amount() >= 20:
number_of_notes = currency.get_amount() // 20
remainder = currency.get_amount() % 20
print(f"Dispensing {number_of_notes} 20$ note")
if remainder != 0:
self.chain.dispense(Currency(remainder))
else:
self.chain.dispense(currency)
class Dollar10Dispenser(DispenseChain):
def __init__(self):
self.chain = None
def set_next_chain(self, next_chain):
self.chain = next_chain
def dispense(self, currency):
if currency.get_amount() >= 10:
number_of_notes = currency.get_amount() // 10
remainder = currency.get_amount() % 10
print(f"Dispensing {number_of_notes} 10$ note")
if remainder != 0:
self.chain.dispense(Currency(remainder))
else:
self.chain.dispense(currency)
class ATMDispenser:
def __init__(self):
self.c1 = Dollar50Dispenser()
c2 = Dollar20Dispenser()
c3 = Dollar10Dispenser()
self.c1.set_next_chain(c2)
c2.set_next_chain(c3)
def dispense_money(self, currency):
if currency.get_amount() % 10 != 0:
print("Amount should be in multiple of 10.")
return
self.c1.dispense(currency)
if __name__ == "__main__":
atm_dispenser = ATMDispenser()
currency = Currency(370)
atm_dispenser.dispense_money(currency)
优缺点:
- 优点
- 分离发送者和接发者
- 链中的灵活性
- 易于扩展
- 易于维护
- 缺点
- 无法保证处理请求(请求可能被忽略)
- 性能开销
- 调试复杂性
应用场景和应用:
- 有多个对象可以处理请求
- 动态添加、修改或删除请求处理器
- 应用: 中间件,GUI事件处理,异常处理, 工作流
命令模式(command)
特点: 把请求变成单独的对象
主要组件:
- 命令(Command)
- 具体命令(ConcreteCommand)
举例: 家电管理
-
使用前
from abc import ABC, abstractmethod class Light(ABC): @abstractmethod def on(self): pass @abstractmethod def off(self): pass class LivingRoomLight(Light): def on(self): print("Living room light is on") def off(self): print("Living room light is off") class KitchenLight(Light): def on(self): print("Kitchen light is on") def off(self): print("Kitchen light is off") class LightController1: def main(self): living_room_light = LivingRoomLight() kitchen_light = KitchenLight() kitchen_light.on() kitchen_light.off() living_room_light.on() living_room_light.off() if __name__ == "__main__": light_controller1 = LightController1() light_controller1.main()
-
使用后
from abc import ABC, abstractmethod from typing import List class Light(ABC): @abstractmethod def on(self): pass @abstractmethod def off(self): pass @abstractmethod def increase_brightness(self): pass class KitchenLight(Light): def on(self): print("Kitchen light is on") def off(self): print("Kitchen light is off") def increase_brightness(self): print("Kitchen light brightness increased") class LivingRoomLight(Light): def on(self): print("Living room light is on") def off(self): print("Living room light is off") def increase_brightness(self): print("Living room light brightness increased") class Command(ABC): @abstractmethod def execute(self): pass @abstractmethod def undo(self): pass class LightOnCommand(Command): def __init__(self, light): self.light = light def execute(self): self.light.on() def undo(self): self.light.off() class LightOffCommand(Command): def __init__(self, light): self.light = light def execute(self): self.light.off() def undo(self): self.light.on() class LightIncreaseCommand(Command): def __init__(self, light): self.light = light def execute(self): self.light.increase_brightness() def undo(self): # Implement an appropriate undo operation, such as decreasing brightness print("TODO") class Fan: def on(self): print("Fan is on") def off(self): print("Fan is off") class FanOnCommand(Command): def __init__(self, fan): self.fan = fan def execute(self): self.fan.on() def undo(self): self.fan.off() class AllLightsOffCommand(Command): def __init__(self, lights: List[Light]): self.lights = lights def execute(self): for light in self.lights: light.off() def undo(self): for light in self.lights: light.on() class RemoteControl: def set_command(self, command): self.command = command def press_button(self): self.command.execute() def press_undo(self): self.command.undo() class LightController3: def main(self): living_room_light = LivingRoomLight() kitchen_light = KitchenLight() fan = Fan() living_room_light_on = LightOnCommand(living_room_light) kitchen_light_off = LightOffCommand(kitchen_light) kitchen_light_increase = LightIncreaseCommand(kitchen_light) fan_on = FanOnCommand(fan) all_lights_off = AllLightsOffCommand([living_room_light, kitchen_light]) remote = RemoteControl() remote.set_command(living_room_light_on) remote.press_button() # Living room light is on remote.press_undo() # Living room light is off remote.set_command(kitchen_light_off) remote.press_button() # Kitchen light is off remote.press_undo() # Kitchen light is on remote.set_command(kitchen_light_increase) remote.press_button() # Increase kitchen light brightness remote.set_command(fan_on) remote.press_button() remote.set_command(all_lights_off) remote.press_button() if __name__ == "__main__": light_controller3 = LightController3() light_controller3.main()
举例: 文字编辑器
import java.util.Stack;
interface Command {
void execute();
void undo();
}
class InsertTextCommand implements Command {
private String textToInsert;
private StringBuilder textEditor;
private int position;
public InsertTextCommand(String text, StringBuilder editor, int position) {
this.textToInsert = text;
this.textEditor = editor;
this.position = position;
}
@Override
public void execute() {
textEditor.insert(position, textToInsert);
}
@Override
public void undo() {
textEditor.delete(position, position + textToInsert.length());
}
}
class DeleteTextCommand implements Command {
private String deletedText;
private StringBuilder textEditor;
private int position;
public DeleteTextCommand(StringBuilder editor, int position, int length) {
this.textEditor = editor;
this.position = position;
this.deletedText = textEditor.substring(position, position + length);
}
@Override
public void execute() {
textEditor.delete(position, position + deletedText.length());
}
@Override
public void undo() {
textEditor.insert(position, deletedText);
}
}
class CommandInvoker {
Stack<Command> commandStack = new Stack<>();
Stack<Command> undoStack = new Stack<>();
public void execute(Command command) {
command.execute();
commandStack.push(command);
}
public void undo() {
if (!commandStack.isEmpty()) {
Command command = commandStack.pop();
command.undo();
undoStack.push(command);
}
}
public void redo() {
if (!undoStack.isEmpty()) {
Command command = undoStack.pop();
command.execute();
commandStack.push(command);
}
}
}
public class TextEditor {
public static void main(String[] args) {
// Initialize the text editor and invoker
StringBuilder textEditor = new StringBuilder();
CommandInvoker invoker = new CommandInvoker();
// Insert "Hello, "
invoker.execute(new InsertTextCommand("Hello, ", textEditor, 0));
// Insert "world!"
invoker.execute(new InsertTextCommand("world!", textEditor, 7));
// Delete ", "
invoker.execute(new DeleteTextCommand(textEditor, 5, 2));
// Current text should be "Helloworld!"
System.out.println("Current text: " + textEditor.toString());
invoker.undo(); // Undo delete - should be back to "Hello, world!"
System.out.println("After undo: " + textEditor.toString());
invoker.undo(); // Undo last insert - should be back to "Hello, "
System.out.println("After undo: " + textEditor.toString());
invoker.redo(); // Redo last insert - should be back to "Hello, world!"
System.out.println("After redo: " + textEditor.toString());
}
}
优缺点:
- 优点
- 动作封装
- 解耦发送者和接受者
- 可拓展性
- 简化和集中错误处理
- 支持撤销和重做功能
- 易与实现宏命令和组合命令
- 缺点
- 复杂度
- 性能开销
常见应用案例:
- 文本编辑器
- 图形编辑器
解释器模式(interpreter)
用途: 解析语言或者表达式
案例: 重复
class Expression:
def interpret(self):
pass
class PrintExpression(Expression):
def __init__(self, message):
self.message = message
def interpret(self):
print(self.message)
class RepeatExpression(Expression):
def __init__(self, repeat_count, expression):
self.repeat_count = repeat_count
self.expression = expression
def interpret(self):
for i in range(self.repeat_count):
self.expression.interpret()
class ReverseExpression(Expression):
def __init__(self, message):
self.message = message
def interpret(self):
print(self.message[::-1])
def main():
command = "REPEAT 3 TIMES: REVERSE Hello"
# Split the command into words based on whitespace
words = command.split(" ")
# Handle the command
if words[0].upper() == "REPEAT":
repeat_count = int(words[1])
# Create the TerminalExpression for the desired command
if words[3].upper() == "PRINT":
expression = PrintExpression(words[4])
elif words[3].upper() == "REVERSE":
expression = ReverseExpression(words[4])
else:
raise ValueError(f"Unsupported command: {words[3]}")
# Create the NonTerminalExpression for REPEAT
repeat_expression = RepeatExpression(repeat_count, expression)
# Interpret the command
repeat_expression.interpret()
if __name__ == "__main__":
main()
案例: 算术
from abc import ABC, abstractmethod
# AbstractExpression
class Expression(ABC):
@abstractmethod
def interpret(self, context):
pass
# TerminalExpression for Numbers
class NumberExpression(Expression):
def __init__(self, number):
self.number = number
def interpret(self, context):
return self.number
# TerminalExpression for Variables
class VariableExpression(Expression):
def __init__(self, variable_name):
self.variable_name = variable_name
def interpret(self, context):
return context.get(self.variable_name)
# NonTerminalExpression for Addition
class AddExpression(Expression):
def __init__(self, left, right):
self.left = left
self.right = right
def interpret(self, context):
return self.left.interpret(context) + self.right.interpret(context)
# Context class
class Context:
def __init__(self):
self.variables = {}
def set(self, name, value):
self.variables[name] = value
def get(self, name):
return self.variables[name]
# Client code
if __name__ == "__main__":
# Set up the context
context = Context()
context.set("x", 5)
context.set("y", 7)
# Build the expression tree
x = VariableExpression("x")
y = VariableExpression("y")
sum = AddExpression(x, y)
# Interpret the expression
result = sum.interpret(context)
print("x + y = ", result) # Output: x + y = 12
优缺点:
- 优点
- 易于拓展或修改
- 灵活性
- 关注点分离
- 代码复用
- 缺点
- 性能问题
- 调试困难
- 复杂性增加
- 适用性有限
适用场景:
- 领域特定语言
- 复杂输入解释
- 可扩展的语言结构
应用案例:
- 编译器和解释器
- 配置文件解析器
- 查询语言解析器
迭代器模式(iterator)
主要作用:
- 遍历集合元素
- 不暴露集合的内部表示
实现方法: 在类中实现Iterable
接口的Iterator<T> iterator()
方法
举例: 书籍管理
import java.util.ArrayList;
import java.util.Comparator;
interface Iterator {
boolean hasNext();
Object next();
}
class Book {
private String title;
public Book(String title) {
this.title = title;
}
public String getTitle() {
return title;
}
}
class Bookshelf {
private ArrayList<Book> books;
public Bookshelf() {
books = new ArrayList<>();
}
public void addBook(Book book) {
books.add(book);
}
public Iterator iterator() {
return new BookIterator();
}
public Iterator sortedIterator() {
return new SortedBookIterator();
}
private class BookIterator implements Iterator {
int index;
public boolean hasNext() {
return index < books.size();
}
public Object next() {
if (this.hasNext()) {
return books.get(index++);
}
return null;
}
}
private class SortedBookIterator implements Iterator {
int index;
ArrayList<Book> sortedBooks;
public SortedBookIterator() {
sortedBooks = new ArrayList<>(books);
sortedBooks.sort(Comparator.comparing(Book::getTitle));
}
public boolean hasNext() {
return index < sortedBooks.size();
}
public Object next() {
if (this.hasNext()) {
return sortedBooks.get(index++);
}
return null;
}
}
}
public class Book3 {
public static void main(String[] args) {
Bookshelf bookshelf = new Bookshelf();
bookshelf.addBook(new Book("Book 1"));
bookshelf.addBook(new Book("Book 2"));
bookshelf.addBook(new Book("Book 3"));
Iterator iterator = bookshelf.sortedIterator();
while (iterator.hasNext()) {
Book book = (Book) iterator.next();
System.out.println(book.getTitle());
}
}
}
优缺点:
- 优点
- 抽象性
- 简化客户端代码
- 支持多种集合类型
- 解耦
- 缺点:
- 代码复杂性
- 性能开销
适用场景:
- 遍历不同类型的集合
- 集合实现可能发生变化
- 提供一致的遍历接口
应用案例:
- 数据库访问
- 文件系统
- 社交网络
中介者模式(mediator)
主要作用:
- 引入中介对象
- 让关系从多对多变为一对多
具体案例: 图形用户界面
优缺点:
- 优点
- 简化对象关系
- 提高灵活性
- 促进低耦合
- 缺点
- 中介者过于庞大
适用场景:
- 复杂通信对象组
- 重用对象
应用案例:
- 聊天应用
- 空中交通控制系统
- GUI框架,MVC架构
- 工作流引擎
备忘录模式(memento)
主要作用: 捕获并保存对象内部的状态
具体案例: 计算器保存结果
import java.util.Stack;
// Originator class
class Calculator {
private int result;
public void add(int value) {
result += value;
}
public void subtract(int value) {
result -= value;
}
public CalculatorMemento save() {
return new CalculatorMemento(result);
}
public void restore(CalculatorMemento memento) {
result = memento.getResult();
}
public int getResult() {
return result;
}
}
// Memento class
class CalculatorMemento {
private final int result;
public CalculatorMemento(int result) {
this.result = result;
}
public int getResult() {
return result;
}
}
// Caretaker class
class CalculatorHistory {
private Stack<CalculatorMemento> history = new Stack<>();
public void save(Calculator calculator) {
history.push(calculator.save());
}
public void undo(Calculator calculator) {
if (!history.isEmpty()) {
calculator.restore(history.pop());
}
}
}
public class CalculatorMain {
public static void main(String[] args) {
Calculator calculator = new Calculator();
CalculatorHistory history = new CalculatorHistory();
calculator.add(5);
calculator.subtract(3);
history.save(calculator); // Save state
System.out.println("Result: " + calculator.getResult()); // Output: Result: 2
calculator.add(8);
System.out.println("Result: " + calculator.getResult()); // Output: Result: 10
history.undo(calculator); // Undo to the previous saved state
System.out.println("Result: " + calculator.getResult()); // Output: Result: 2
}
}
优缺点:
- 优点:
- 封装性
- 简易恢复和撤销
- 简化发起人
- 缺点
- 增加内存使用
- 性能开销
- 复杂性
适用场景:
- 需要维护对象状态的历史记录
- 不想暴露复杂内部状态
应用案例:
- 文本编辑器
- 绘图应用程序
- 数据库系统
- 游戏开发
- 版本控制系统
观察者模式(observer)
主要作用:
- 定义一对多的依赖关系
- 让多个观察者同时监听一个主题对象
代码示例:
class Subject:
def __init__(self):
self._observers = []
def attach(self, observer):
if observer not in self._observers:
self._observers.append(observer)
def detach(self, observer):
try:
self._observers.remove(observer)
except ValueError:
pass
def notify(self):
for observer in self._observers:
observer.update(self)
class Observer:
def update(self, subject):
pass
class ConcreteObserverA(Observer):
def update(self, subject):
print("ConcreteObserverA: Reacted to the event")
class ConcreteObserverB(Observer):
def update(self, subject):
print("ConcreteObserverB: Reacted to the event")
# 使用观察者模式
subject = Subject()
observer_a = ConcreteObserverA()
observer_b = ConcreteObserverB()
subject.attach(observer_a)
subject.attach(observer_b)
# 触发事件
subject.notify()
优缺点:
- 优点
- 广播通信
- 低耦合
- 支持事件处理
- 缺点
- 开销问题
- 实现复杂
适用场景:
- 多对象间实现广播通信
- 一个对象的改变需要同时改变其他对象
应用案例:
- 社交媒体平台
- 股票市场
- GUI工具(e.g.
javax.awt
) - 实时消息系统
状态模式(state)
主要作用: 允许对象内部状态改变时改变它的行为【对象的方法调用的是对象内部状态的方法】
优缺点:
- 优点
- 封装性
- 简化代码
- 易于扩展
- 缺点
- 类数量增多
- 逻辑复杂
适用场景:
- 行为随状态而改变
- 条件、分支语句的替代者
应用案例:
- 游戏角色状态切换
- 网络连接状态管理
- 订单状态管理
策略模式(strategy)
主要作用: 定义一系列算法,并封装起来,使它们可以相互替换
优缺点:
- 优点
- 提高灵活性
- 提高可维护性
- 更好地处理if-else语句
- 缺点
- 复杂性
- 间接性
适用场景:
- 动态选择算法
- 条件、分支语句的替代者
应用案例:
- 支付方式
- 压缩和解压缩算法
- 图像渲染
模版方法模式(template)
主要作用: 定义算法骨架
优缺点:
- 优点
- 代码复用
- 统一算法框架
- 封装不变,拓展可变
- 缺点
- 增加复杂性
- 父类改动的影响太大
适用场景:
- 一次性实现算法的不变部分
- 集中公共行,避免代码重复
应用案例:
- 数据库访问
- GUI设计
- 框架和库(e.g. KeyNodeFinder)
注意事项: 可以将父类中只有模版方法才会调用的方法改为private
访问者模式(visitor)
具体案例: 图形绘制更改
- 使用前:
interface Shape { void draw(); void resize(); } class Circle implements Shape { public void draw() { System.out.println("Drawing a circle"); } public void resize() { System.out.println("Resizing a circle"); } } class Rectangle implements Shape { public void draw() { System.out.println("Drawing a rectangle"); } public void resize() { System.out.println("Resizing a rectangle"); } } public class ShapeMain1 { public static void main(String[] args) { Shape circle = new Circle(); Shape rectangle = new Rectangle(); circle.draw(); rectangle.draw(); circle.resize(); rectangle.resize(); } }
- 适用后:
interface Shape { void accept(Visitor visitor); } class Circle implements Shape { public void accept(Visitor visitor) { visitor.visit(this); } } class Rectangle implements Shape { public void accept(Visitor visitor) { visitor.visit(this); } } interface Visitor { void visit(Circle circle); void visit(Rectangle rectangle); } class DrawVisitor implements Visitor { public void visit(Circle circle) { System.out.println("Drawing a circle"); } public void visit(Rectangle rectangle) { System.out.println("Drawing a rectangle"); } } class ResizeVisitor implements Visitor { public void visit(Circle circle) { System.out.println("Resizing a circle"); } public void visit(Rectangle rectangle) { System.out.println("Resizing a rectangle"); } } public class ShapeMain2 { public static void main(String[] args) { Shape circle = new Circle(); Shape rectangle = new Rectangle(); Visitor drawVisitor = new DrawVisitor(); Visitor resizeVisitor = new ResizeVisitor(); circle.accept(drawVisitor); rectangle.accept(drawVisitor); circle.accept(resizeVisitor); rectangle.accept(resizeVisitor); } }
主要作用:
- 将数据结构和数据操作分离
- 使操作集合可以独立于数据结构变化
其他案例: 购物车系统
优缺点:
- 优点
- 分离操作和数据结构
- 增加新操作更容易
- 集中化操作
- 缺点
- 加新数据结构困难
- 破坏封装
适用场景:
- 数据结构稳定,操作易变
- 一个对象的操作之间无关联
应用案例:
- 编译器
- 文档转换