设计模式学习笔记
系统学习 设计模式 0 239

参考资料:

  1. 视频课程
  2. 图文大纲
  3. 配套源码
  4. 相关文档

用途:

  1. 减少垃圾代码,提高代码库的可维护性和延展空间
  2. 减少沟通成本(直接用最佳实践)
  3. 开拓思维

7大原则

  1. 面对对象设计: 开闭原则,依赖倒置原则
    • 开闭原则(The Open Closed Principle, OCP): 对扩展开放,对修改关闭。
    • 依赖倒置(The Dependency Inversion Principle, DIP): 要依赖于抽象,不要依赖于具体。
  2. 拆分解构: 单一职责原则,接口隔离原则
    • 单一职责(The Single Responsibility Principle, SRP)【对业务】: 让一个类只负责一件事。
    • 接口隔离(The Interface Segregation Principle, ISP)【对架构】: 一个类对另一个类的依赖应该建立在最小的接口上。
  3. 类之间的通信: 合成复用原则,里氏替换原则,迪米特法则
    • 合成复用: 尽量使用组合/聚合关系,少用继承。
    • 里氏替换(The Liskov Substitution Principle, LSP): 任何基类可以出现的地方,子类一定可以出现。
    • 迪米特法则/最少知识原则(Least Knowledge Principle, LKP): 一个对象对其他对象知道的越少越好,不和陌生人说话。

其他:

  1. 共同封闭原则: 一起修改的类,应该组合在一起(同一个包里)。如果必须修改应用程序里的代码,我们希望所有的修改都发生在一个包里(修改关闭),而不是遍布在很多包里。
  2. 稳定抽象原则: 最稳定的包应该是最抽象的包,不稳定的包应该是具体的包,即包的抽象程度跟它的稳定性成正比。
  3. 稳定依赖原则: 包之间的依赖关系都应该是稳定方向依赖的,包要依赖的包要比自己更具有稳定性。

注意: 也有总结为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)

依赖倒置原则

定义:

  1. 高层不应该依赖底层,两者应该基于抽象【抽象比细节稳定】
  2. 抽象不应该依赖细节,细节应该依赖抽象

说明: 高层模块包含一个应用程序中重要的策略选择和业务模块,如果高层模块依赖于低层模块,那么低层模块的改动就会直接影响到高层模块,从而迫使高层模块也需要改动。依赖于抽象意味着:

  1. 任何变量都不应该持有一个指向具体类的指针或者引用;
  2. 任何类都不应该从具体类派生;
  3. 任何方法都不应该覆写它的任何基类中的已经实现的方法。

好处: 结构更稳定,更好地应对需求变化

模式: 工厂方法(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')

合成复用原则

说明: 尽量使用对象聚合/组合,而不是继承关系达到软件复用的目的 【聚合/组合>继承】

  • 继承复用(白箱复用):
    1. 优点: 简单、容易实现
    2. 缺点: 破坏了封装性、耦合高、限制灵活性
  • 合成复用:
    1. 优点: 维持封装性、降低耦合度、灵活性高
    2. 缺点: 有较多的对象需要管理

示例:

  • 使用前:

    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()

接口隔离原则

定义: 不应该强迫客户依赖于它们不用的方法。

说明: 使用多个专门的接口比使用单一的总接口要好。

  1. 客户端不应该依赖它不用等接口 => 低耦合
    1. 依赖不用的接口,会让接口变动的风险会加大
    2. 客户端不应被迫使用对其而言无用的方法或功能
  2. 类之间的依赖应该建立在最小的接口上面 => 高内聚
    1. 把庞大臃肿的接口拆分成更小和更具体的接口
    2. 最小接口: 满足项目需求的相似的功能

注意:

  1. 设计粒度太小范儿会适得其反
  2. 设计粒度参考,一个接口只服务于一个子模块或者业务逻辑

对比"单一职责原则":

  1. 约束偏向: 接口隔离偏向约束架构设计,单一职责偏向约束业务
  2. 细化程度: 单一职责更精细,接口隔离注重相似接口的隔离

示例:

  • 使用前:

    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关系,子类需要能够当成父类来使用,并且需要比父类更特殊。如果不满足这个原则,那么各个子类的行为上就会有很大差异,增加继承体系的复杂度。换句话说,任何基类出现的地方,子类一定可以出现。

理由:

  1. 继承关系给程序带来侵入性【父类修改子类可能也要改】
  2. 避免程序升级后的兼容性
  3. 避免程序出错

原则:

  1. 保证基类所拥有的性质在子类中依然成立
  2. 子类扩展父类的功能,但是不能改变父类原有的功能

规范:

  1. 子类必须完全实现父类的抽象方法【Java可以保证】,但不能覆盖父类的非抽象方法
  2. 子类可以实现自己特有的方法
  3. 当子类的方法实现父类的抽象方法时,方法的后置条件(方法的返回值)要比父类更严格【Java可以保证】
  4. 子类的实例可以替代父类的实例,但反之不成立

注意:

  1. 不遵守这一原则 => 当前代码没问题,未来出错率会提高
  2. 聚合/组合 > 继承(合成复用原则)

示例:

  • 错误案例(规范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个设计模式

分为三大类: 行为型、结构型、创建型

创建型模式:

  • 帮助我们创建类或者对象
  • 核心思想: 把对象的创建和使用分离,使两者能相对独立地变换
  • 相关设计模式
    1. 抽象工厂模式(Abstract Factory): 提供创建一系列相关或相互依赖对象的接口
    2. 生成器模式(Builder): 使用多个简单对象,构建成一个复杂对象
    3. 工厂方法模式(Factory Method): 父类中提供一个创建对象的共同接口,让子类决定实例化具体的对象
    4. 原型模式 (Prototype): 提供原型用于创建重复的对象
    5. 单例模式(Singleton): 保证一个类只有一个实例,仅提供一个访问它的全局访问点

结构性模式:

  • 涉及如何组合各种对象以便获得更好、更灵活的结构
  • 更多地通过组合与运行期的动态结合来实现更灵活的功能
  • 相关设计模式
    1. 适配器模式(Adapter): 融合两个不兼容的类
    2. 桥接模式(Bridge): 将抽象与实现分离,使其可以独立变化
    3. 组合模式(Composite): 将对象组成树形结构,让单个对象和组合对象的使用具有一致性
    4. 装饰模式(Decorator): 动态给对象添加额外的职责
    5. 外观模式(Facade): 用一个统一接口来代理多个类的访问
    6. 享元模式(Flyweight): 使用对象池共享细粒度的对象,以減少内存占用
    7. 代理模式(Proxy): 提供代理以控制对特定对象的访问控制

行为型模式:

  • 用于描述类或者对象是怎样交互和如何分配职责的。
  • 涉及到算法和对象间的职责分配,描述一组对象应该如何协作来完成一个整体的任务。
  • 相关设计模式
    1. 责任链模式(Chain of Responsibility): 将请求沿着链去处理,使多个对象都有机会处理请求
    2. 命令模式(Command): 将请求封装成命令,从而可用不同的请求对客户端进行参数化
    3. 解释器模式(Interpreter): 定义一个语言的语法,并提供解释器解释语言中的句子
    4. 迭代器模式(lterator): 提供一种方法顺序访问一个聚合对象中的各个元素,不暴露内部细节
    5. 中介者模式(Mediator): 用一个中介对象封装一系列的对象交互,实现多方的松耦合
    6. 备忘录模式(Memento): 保存对象的状态,在需要时进行恢复
    7. 观察者模式(Observer): 监听一个主对象,状态改变时,通知所有监听它的观察者
    8. 状态模式(Sate): 允许对象在内部状态改变时,同时改变它的行为
    9. 策略模式(Strategy): 封装不同的算法,让算法之间能互相替换
    10. 模板方法模式(Template Method): 定义算法框架,把待定的步骤留给子类实现
    11. 访问者模式(Visitor): 在稳定数据结构的前提下,定义新的操作行为

创建型模式

抽象工厂模式(abstract_factory)

场景: 提供统一的接口创建一系列相关的产品

  • 不同厂商要生产不同款式的不同型号的车
  • 游戏服装套装,通常一整套一起换
  • 操作系统的组件模块,同一组模块需要对应相同的系统

思路:

说明:

  1. 提供一个创建一系列相关或者相互依赖对象的借口,而不制定他们具体的类
  2. 抽象工厂模式讲一组对象的实现细节与他们的一般使用分离开

代码:

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()

优缺点:

  • 优点:
    1. 规范了创建相同系列产品的方式
    2. 只需要暴露创建接口,可以隐藏实现细节
    3. 容易改变产品的系列
  • 缺点:
    1. 扩展产品库需要额外工作:除了产品代码外,还需要改动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();
    }

}

优缺点:

  • 优点
    1. 分步创建,更加灵活
    2. 可以复用相同的制作代码
    3. 严格遵循单一职责原则
  • 缺点
    1. 代码整体复杂度增加

对比"抽象工厂":

生成器 抽象工厂
目的 构建复杂对象 创建一系列相关联的对象
创建对象方式 多步骤创建 单一步骤创建

工厂方法模式(factory_method)

场景: 将产品的实例化延迟到具体工厂中完成

  1. 创建对象需要使用大量重复代码
  2. 无需客户端知道具体产品的类别和依赖关系,只需要知道对应工厂就好

代码:

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. 复制复杂的数据结构

原型模式: 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 WilsonTennisRacket(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);
    }
}

优缺点:

  • 优点
    1. 提高代码的可复用性
    2. 增加系统的灵活度
    3. 减少复制的时间和资源
  • 缺点
    1. 增加复杂度
    2. 原型复制的不一致
    3. 内存使用可能会被提高

单例模式(singleton)

场景:

  1. 资源分享: 数据库
  2. 配置管理
  3. 缓存
  4. 日志管理
  5. 对象工厂
  6. 线程池本身的创建【固定线程池的创建可以看作"多例模式"】

作用:

  1. 保证一个类只有一个实例
  2. 为该实例提供了一个全局唯一的访问节点(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()

优缺点:

  • 优点
    1. 提高调用速度
    2. 更有效利用资源
    3. 防止资源冲突和一致性问题
  • 缺点
    1. 潜在的竞争条件(race conditions)和线程安全(thread-safety)问题

结构性模式

适配器模式(adapter)

作用: 让接口不兼容的对象能够合作

场景: e.g. 文件输出跟输入的格式不一样,需要中间件来转换

  1. 基本应用: 支持多接口,重用现有的代码
  2. 连接遗留代码和新系统
  3. 连接第三方库
  4. 单元测试: 模拟真正对象的行为(Mock objects)

角色:

  1. 请求者Client: 调用服务的角色
  2. 目标Target: 定义了Client要使用的功能
  3. 转换对象Adaptee: 需要被适配器转换的对象
  4. 适配器Adapter: 实现转换功能的对象

实现方法:

  1. 类适配器模式,用继承

    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.")

  2. 对象适配器模式,用组合

    # 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.")

  3. 双向适配器

    # 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())

优缺点:

  • 优点
    1. 把转换代码从业务逻辑中分离出来
    2. 在不修改现有代码的情况下实现转化
    3. 让代码更加模块化而且可以复用
  • 缺点
    1. 代码的整体复杂度会增加
    2. 重复代码
    3. 很难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();
    }
}

优缺点:

  • 优点
    1. 让抽离和实现独立
    2. 灵活和可拓展的架构
    3. 增加代码复用,可读性和可维护性
    4. 简化测试和调试
  • 缺点
    1. 增加复杂度
    2. 更多规划和设计工作
    3. 不必要的抽象和冗余代码
    4. 可读性降低

应用场景

  1. 隐藏实现细节
  2. 避免抽象和实现的绑定
  3. 提高代码可拓展性
  4. 应用案例:GUI框架,绘图程序,数据库驱动系统

和适配器模式区别

  1. 适配器模式是将两个不兼容的接口连起来(针对已有代码)
  2. 桥接模式是前期设计时分离抽象与实现

组合模式(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()

特点:

  1. 递归组合
  2. 树状结构
  3. 统一处理处理所有对象

优缺点:

  • 优点

    1. 简化客户端操作
    2. 易于扩展
  • 缺点

    1. 可能违反开闭原则

应用场景:

  1. 层次结构系统
  2. 对单个对象和组合对象进行相同操作

注意事项:

  1. 确保组件接口适合叶子节点和组合对象
  2. 把可选方法放入具体的叶子节点

装饰模式(decorator)

特点:

  1. 灵活拓展新功能
  2. 动态添加额外职责

举例: 公司通知发送

// 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);
    }
}

说明:

  1. 其实python中有直接实现类似结构的装饰器

优缺点:

  • 优点
    1. 提高灵活性和可扩展性
    2. 简便不同的组合
    3. 提高可维护性
  • 缺点
    1. 代码的复杂性
    2. 增加性能开销

应用场景:

  1. 在不影响其他对象的情况下,为单个对象添加新功能
  2. 动态组合多种可选功能
  3. 具体应用: 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);
    }
}

优缺点:

  • 优点
    1. 简化交互方式
    2. 解耦合
    3. 提高可维护性
  • 缺点
    1. 不符合开闭原则
    2. 隐藏了潜在问题

应用场景:

  1. 子系统接口复杂
  2. 需要将子系统划分为多个层次
  3. 解耦客户端与子系统
  4. 具体应用: 复杂的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()

目的: 最小化内存的使用

特点:

  1. 共享相似实例
  2. 把实例的共享状态和不共享状态分开

案例: 士兵游戏

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();
    }
}

优缺点:

  • 优点
    1. 减少内存使用
    2. 提高性能
    3. 可扩展性
  • 缺点
    1. 复杂度: 内外部状态,享元工厂
    2. 多线程环境困难
    3. 适用性有限
  • 应用场景: 需要大量共享数据
    1. 文字编辑器和处理器
    2. 图形应用
    3. 游戏开发
    4. 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. 让代理充当其他事物的接口

不同类型代理: 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"
    }
}

优缺点:

  • 优点:
    1. 关注点分离
    2. 访问控制
    3. 延迟实例化
    4. 远程访问
    5. 缓存
    6. 额外的行为
  • 缺点:
    1. 增加复杂性
    2. 间接性
    3. 性能开销

应用场景和应用:

  1. 访问控制
  2. 缓存
  3. 保护代理
  4. 远程对象
  5. 智能引用
  6. 其他: 日志记录、监控和审计

行为型模式

责任链模式(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");
        }
    }   

特点: 允许多个对象按顺序处理请求或任务

主要组件:

  1. 处理器接口(handler)
  2. 具体处理器(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)

优缺点:

  • 优点
    1. 分离发送者和接发者
    2. 链中的灵活性
    3. 易于扩展
    4. 易于维护
  • 缺点
    1. 无法保证处理请求(请求可能被忽略)
    2. 性能开销
    3. 调试复杂性

应用场景和应用:

  1. 有多个对象可以处理请求
  2. 动态添加、修改或删除请求处理器
  3. 应用: 中间件,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());
   }
}

优缺点:

  • 优点
    1. 动作封装
    2. 解耦发送者和接受者
    3. 可拓展性
    4. 简化和集中错误处理
    5. 支持撤销和重做功能
    6. 易与实现宏命令和组合命令
  • 缺点
    1. 复杂度
    2. 性能开销

常见应用案例:

  1. 文本编辑器
  2. 图形编辑器

解释器模式(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

优缺点:

  • 优点
    1. 易于拓展或修改
    2. 灵活性
    3. 关注点分离
    4. 代码复用
  • 缺点
    1. 性能问题
    2. 调试困难
    3. 复杂性增加
    4. 适用性有限

适用场景:

  1. 领域特定语言
  2. 复杂输入解释
  3. 可扩展的语言结构

应用案例:

  1. 编译器和解释器
  2. 配置文件解析器
  3. 查询语言解析器

迭代器模式(iterator)

主要作用:

  1. 遍历集合元素
  2. 不暴露集合的内部表示

实现方法: 在类中实现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());
        }
    }
}

优缺点:

  • 优点
    1. 抽象性
    2. 简化客户端代码
    3. 支持多种集合类型
    4. 解耦
  • 缺点:
    1. 代码复杂性
    2. 性能开销

适用场景:

  1. 遍历不同类型的集合
  2. 集合实现可能发生变化
  3. 提供一致的遍历接口

应用案例:

  1. 数据库访问
  2. 文件系统
  3. 社交网络

中介者模式(mediator)

主要作用:

  1. 引入中介对象
  2. 让关系从多对多变为一对多

具体案例: 图形用户界面

优缺点:

  • 优点
    1. 简化对象关系
    2. 提高灵活性
    3. 促进低耦合
  • 缺点
    1. 中介者过于庞大

适用场景:

  1. 复杂通信对象组
  2. 重用对象

应用案例:

  1. 聊天应用
  2. 空中交通控制系统
  3. GUI框架,MVC架构
  4. 工作流引擎

备忘录模式(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
    }
}

优缺点:

  • 优点:
    1. 封装性
    2. 简易恢复和撤销
    3. 简化发起人
  • 缺点
    1. 增加内存使用
    2. 性能开销
    3. 复杂性

适用场景:

  1. 需要维护对象状态的历史记录
  2. 不想暴露复杂内部状态

应用案例:

  1. 文本编辑器
  2. 绘图应用程序
  3. 数据库系统
  4. 游戏开发
  5. 版本控制系统

观察者模式(observer)

主要作用:

  1. 定义一对多的依赖关系
  2. 让多个观察者同时监听一个主题对象

优缺点:

  • 优点
    1. 广播通信
    2. 低耦合
    3. 支持事件处理
  • 缺点
    1. 开销问题
    2. 实现复杂

适用场景:

  1. 多对象间实现广播通信
  2. 一个对象的改变需要同时改变其他对象

应用案例:

  1. 社交媒体平台
  2. 股票市场
  3. GUI工具
  4. 实时消息系统

状态模式(state)

主要作用: 允许对象内部状态改变时改变它的行为【对象的方法调用的是对象内部状态的方法】

优缺点:

  • 优点
    1. 封装性
    2. 简化代码
    3. 易于扩展
  • 缺点
    1. 类数量增多
    2. 逻辑复杂

适用场景:

  1. 行为随状态而改变
  2. 条件、分支语句的替代者

应用案例:

  1. 游戏角色状态切换
  2. 网络连接状态管理
  3. 订单状态管理

策略模式(strategy)

主要作用: 定义一系列算法,并封装起来,使它们可以相互替换

优缺点:

  • 优点
    1. 提高灵活性
    2. 提高可维护性
    3. 更好地处理if-else语句
  • 缺点
    1. 复杂性
    2. 间接性

适用场景:

  1. 动态选择算法
  2. 条件、分支语句的替代者

应用案例:

  1. 支付方式
  2. 压缩和解压缩算法
  3. 图像渲染

模版方法模式(template)

主要作用: 定义算法骨架

优缺点:

  • 优点
    1. 代码复用
    2. 统一算法框架
    3. 封装不变,拓展可变
  • 缺点
    1. 增加复杂性
    2. 父类改动的影响太大

适用场景:

  1. 一次性实现算法的不变部分
  2. 集中公共行,避免代码重复

应用案例:

  1. 数据库访问
  2. GUI设计
  3. 框架和库(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);
        }
    }

主要作用:

  1. 将数据结构和数据操作分离
  2. 使操作集合可以独立于数据结构变化

其他案例: 购物车系统

优缺点:

  • 优点
    1. 分离操作和数据结构
    2. 增加新操作更容易
    3. 集中化操作
  • 缺点
    1. 加新数据结构困难
    2. 破坏封装

适用场景:

  1. 数据结构稳定,操作易变
  2. 一个对象的操作之间无关联

应用案例:

  1. 编译器
  2. 文档转换
编写
预览