行为型设计模式:策略模式、模板方法模式与观察者模式

在软件开发中,设计模式是解决常见问题的通用解决方案。行为型设计模式关注对象之间的通信,通过定义对象间的交互方式来实现特定的功能。本文将深入解析三种行为型设计模式:策略模式、模板方法模式和观察者模式,并结合实际案例进行分析。

一、策略模式(Strategy Pattern)

(一)定义

策略模式定义了一系列的算法,将它们一个个封装起来,并使它们可以相互替换。其核心思想是将算法的变化与使用算法的代码分离开来,使得算法的变化不会影响到使用算法的代码。

(二)应用场景

  1. 电商平台促销活动:如淘宝天猫双十一的打折、满减、返利等促销活动,每种活动策略都可以封装为一个策略类,方便随时替换。

  2. 旅行方式选择:老王计划外出旅游,可以选择骑自行车、坐汽车、飞机等不同的旅行方式,每种方式都是一个策略。

  3. 布局管理器:Java AWT中的LayoutManager,根据不同的布局需求选择不同的布局策略。

(三)角色

  • Context(上下文):封装对策略的引用,提供一个接口供客户端调用,屏蔽高层模块对策略、算法的直接访问。

  • Strategy(策略角色):定义所有支持算法的公共接口,抽象策略角色,是对策略、算法家族的抽象。

  • ConcreteStrategy(具体策略角色):实现抽象策略中定义的操作,即实现具体的算法。

(四)实现案例

以下是一个电商促销活动的实现案例:

// 定义策略接口
public abstract class Strategy {
    public abstract double computePrice(ProductOrder productOrder);
}

// 具体策略:正常活动
public class NormalActivity extends Strategy {
    @Override
    public double computePrice(ProductOrder productOrder) {
        return productOrder.getOldPrice();
    }
}

// 具体策略:折扣活动
public class DiscountActivity extends Strategy {
    private double rate;

    public DiscountActivity(double rate) {
        this.rate = rate;
    }

    @Override
    public double computePrice(ProductOrder productOrder) {
        return productOrder.getOldPrice() * rate;
    }
}

// 具体策略:优惠券活动
public class VoucherActivity extends Strategy {
    private double voucher;

    public VoucherActivity(double voucher) {
        this.voucher = voucher;
    }

    @Override
    public double computePrice(ProductOrder productOrder) {
        if (productOrder.getOldPrice() > voucher) {
            return productOrder.getOldPrice() - voucher;
        } else {
            return 0;
        }
    }
}

// 上下文类
public class PromotionContext {
    private Strategy strategy;

    public PromotionContext(Strategy strategy) {
        this.strategy = strategy;
    }

    public double executeStrategy(ProductOrder productOrder) {
        return strategy.computePrice(productOrder);
    }
}

// 使用
public static void main(String[] args) {
    ProductOrder productOrder = new ProductOrder(800, 1, 32);
    PromotionContext context;

    // 不同策略算出不同的活动价格
    context = new PromotionContext(new NormalActivity());
    System.out.println("NormalActivity = " + context.executeStrategy(productOrder));

    context = new PromotionContext(new DiscountActivity(0.8));
    System.out.println("DiscountActivity = " + context.executeStrategy(productOrder));

    context = new PromotionContext(new VoucherActivity(100));
    System.out.println("VoucherActivity = " + context.executeStrategy(productOrder));
}

(五)优点

  1. 满足开闭原则:增加新的策略时,无需修改上下文类的代码。

  2. 避免多重条件判断:减少代码中的if-else嵌套,使代码更加清晰。

(六)缺点

  1. 策略类数量增多:每个策略都是一个类,可能导致类的数量过多。

  2. 行为过多导致类膨胀:策略类中可能包含过多的行为,导致类的复杂度增加。

二、模板方法模式(Template Method Pattern)

(一)定义

模板方法模式定义了一个操作中的算法骨架,将算法的一些步骤延迟到子类中。子类可以不改变算法结构的情况下,重新定义算法的某些特定步骤。

(二)应用场景

  1. Servlet的service()方法:在Java Web开发中,HttpServlet类的service()方法是一个模板方法,不同的子类(如doGet()doPost())实现了具体的逻辑。

  2. 项目里程碑把控:项目生命周期中的固定步骤(如需求评审、设计)可以作为模板方法,而其他步骤(如开发、测试)则根据具体项目进行扩展。

(三)角色

  • 抽象模板(Abstract Template):定义了一个模板方法,这个模板方法是一个具体方法,给出了一个顶级算法骨架。

  • 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。

  • 基本方法:是整个算法中的一个步骤,包括抽象方法和具体方法。

  • 具体模板(Concrete Template):实现父类所定义的一个或多个抽象方法,是顶级算法逻辑的组成步骤。

(四)实现案例

以下是一个项目里程碑把控的实现案例:

// 抽象类
public abstract class AbstractClass {
    public void templateMethod() {
        specificMethod();
        abstractMethod1();
        abstractMethod2();
    }

    public void specificMethod() {
        System.out.println("抽象类中的具体方法被调用");
    }

    public abstract void abstractMethod1();
    public abstract void abstractMethod2();
}

// 具体类
public class ConcreteClass extends AbstractClass {
    @Override
    public void abstractMethod1() {
        System.out.println("具体类实现抽象方法1");
    }

    @Override
    public void abstractMethod2() {
        System.out.println("具体类实现抽象方法2");
    }
}

// 使用
public static void main(String[] args) {
    AbstractClass class1 = new ConcreteClass();
    class1.templateMethod();
}

(五)优点

  1. 扩展性好:对不变的代码进行封装,对可变的进行扩展,符合开闭原则。

  2. 提高代码复用性:将相同部分的代码放在抽象的父类中,将不同的代码放入不同的子类中。

(六)缺点

  1. 类的数量增加:每个不同的实现都需要一个子类来实现,可能导致类的数量过多,使系统变得复杂。

三、观察者模式(Observer Pattern)

(一)定义

观察者模式定义了对象间的一种一对多的依赖关系,使得每当一个对象改变状态时,所有依赖于它的对象都会得到通知并自动更新。也称为发布订阅模式(Publish/Subscribe)。

(二)应用场景

  1. 消息通知:如邮件通知、广播通知、微信朋友圈、微博私信等。

  2. UI组件更新:当一个对象的状态改变时,需要更新多个依赖的UI组件。

(三)角色

  • Subject(主题):持有多个观察者对象的引用,提供接口可以增加和删除观察者对象。

  • Observer(抽象观察者):为具体观察者定义一个接口,在得到主题的通知时更新自己。

  • ConcreteSubject(具体主题):将有关状态存入具体观察者对象,在内部状态改变时,给所有登记过的观察者发出通知。

  • ConcreteObserver(具体观察者):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题的状态保持一致。

(四)实现案例

以下是一个“老王上班摸鱼”的实现案例:

// 主题类
public class Subject {
    private List observerList = new ArrayList<>();

    public void addObserver(Observer observer) {
        this.observerList.add(observer);
    }

    public void deleteObserver(Observer observer) {
        this.observerList.remove(observer);
    }

    public void notifyAllObserver() {
        for (Observer observer : observerList) {
            observer.update();
        }
    }
}

// 观察者接口
public interface Observer {
    void update();
}

// 具体主题:老板
public class BossConcreteSubject extends Subject {
    public void doSomething() {
        System.out.println("老板完成自己的工作");
        System.out.println("视察公司工作情况");
        super.notifyAllObserver();
    }
}

// 具体观察者:老王
public class LWConcreteObserver implements Observer {
    @Override
    public void update() {
        System.out.println("老王发现领导到来,暂停在线摸鱼,回归工作");
    }
}

// 具体观察者:Anna
public class AnnaConcreteObserver implements Observer {
    @Override
    public void update() {
        System.out.println("Anna小姐姐发现领导到来,暂停在线摸鱼,回归工作");
    }
}

// 使用
public static void main(String[] args) {
    BossConcreteSubject subject = new BossConcreteSubject();
    Observer lwObserver = new LWConcreteObserver();
    Observer annaObserver = new AnnaConcreteObserver();

    subject.addObserver(lwObserver);
    subject.addObserver(annaObserver);

    subject.doSomething();
}

(五)优点

  1. 降低耦合关系:目标与观察者之间建立了一套触发机制,降低了它们之间的耦合关系。

  2. 抽象耦合:观察者和被观察者是抽象耦合的,便于扩展。

(六)缺点

  1. 循环依赖问题:如果观察者和观察目标之间存在循环依赖,可能会触发它们之间的循环调用,导致系统崩溃。

  2. 通知效率问题:如果一个被观察者对象有很多直接和间接的观察者,通知所有观察者可能会花费很多时间。

行为型设计模式在软件开发中具有重要的作用,策略模式、模板方法模式和观察者模式是其中的典型代表。策略模式通过封装算法的变化,提供了一种灵活的解决方案;模板方法模式通过定义算法骨架,实现了代码的复用和扩展;观察者模式通过定义对象间的依赖关系,实现了对象间的松耦合通信。在实际开发中,合理运用这些设计模式,可以提高代码的可维护性和可扩展性,降低系统的复杂度。

你可能感兴趣的:(设计模式,java,开发语言,设计模式,策略模式,模板方法模式,观察者模式)