行为设计模式

156 阅读4分钟

我的理解:所谓的行为模式,就是根据不同的应用场景,将原有对象中的易变的行为动作抽象出来,和原有对象进行解耦,所以归类成行为设计模式。这类设计模式的学习一定要结合业务场景之后的迭代才能够体现出设计模式的优点。其中策略模式、中介者模式和责任链模式因为没有什么难以理解的,就不赘述了

访问者模式 (Visitor-Pattern)

概念

  • 通过访问者模式来抽离原有类中的分支,提升原有类对象的扩展性,保持顶层设计

应用场景

  • 解决现有已经稳定的业务场景结构和易变的操作之间的耦合,对两个部分进行解耦,使得操作可以随意的变动而不影响原有稳定业务结构
  • 假设业务场景:水果店购物车购买水果。苹果单价1元,桃子单价2元,西瓜单价3元。购物卡形式消费购买苹果超过2斤,打八折;桃子3斤打五折,西瓜不打折。现金购买不打折。
    • 方案一:将算价逻辑内聚到苹果、桃子、西瓜当中,但是随着消费方式的增加。水果中的算价逻辑会发生膨胀,持续恶化,无法维护;并且每新进一种水果,并且在实现提供价格的时候,得考虑到各种消费方式
    • 方案二:以访问者模式,抽离水果的折扣算价逻辑,水果只提供基础单价,有消费方式来聚合各种水果的最终价格

UML

访问者模式.png

Coding

手打的代码,就不写构造函数了

step1 现金购买水果

  • Fruit
public interface Fruit {
    
    public Integer getCount();
    
    public Integer getBasePrice();
    
    public Integer getPrice(PayMode paymode);
    
}
  • PayMode

public interface PayMode {
    public Integer getPrice(Fruit fruit);
}

  • Apple
public class Apple implements Fruit {
    private Integer count = 1;
    
    private Integer basePrice = 0;
    
    public Integer getCount() {
        return this.count;
    }
    
    public Integer getBasePrice() {
        return this.basePrice;
    }
    
    public Integer getPrice(PayMode payMode) {
        return payMode.getPrice(this);
    }
}
  • Peach
public class Peach implements Fruit {
    private Integer count = 2;
    
    private Integer basePrice = 0;
    
    public Integer getCount() {
        return this.count;
    }
    
    public Integer getBasePrice() {
        return this.basePrice;
    }
    
    public Integer getPrice(PayMode payMode) {
        return payMode.getPrice(this);
    }
}
  • Cash
public void Cash implements PayMode {
    
    public Integer getPrice(Fruit fruit) {
        if (fruit == null) {
            throw new IllegalArgumentException();
        }
        return fruit.getCount() * fruir.getBasePrice();
    }
}
  • ShopCart(购物车)
public class ShopCart {
    private List<Fruit> fruits = Lists.newArrayList();
    
    public void add(Fruit fruit) {
        fruits.add();
    }
    
    public void getTotalPricee(PayMode payMode) {
        Integer totalPrice = 0;
        for (Fruit fruit : fruits) {
            totalPrice = totalPrice + fruit.getPrice(payMode);
        }
        return totalPrice
    }
}
  • ClientDemo
public class ClientDemo {
    public static void main(String[] args) {
        ShopCart shopCart = new ShopCart();
        Apple apple = new Apple(3);
        Peach peach = new Peach(5);
        shopCart.add(apple);
        shopCart.add(peach);
        
        totalPrice = shopCart.getTotalPrice(new Cash());
    }
}

step2 新进品类,西瓜,整个结构不需要改动

  • Watermelon
public class Watermelon implements Fruit {
    private Integer count = 0;
    
    private Integer basePrice = 3;
    
    public Integer getCount() {
        return this.count;
    }
    
    public Integer getBasePrice() {
        return this.basePrice;
    }
    
    public Integer getPrice(PayMode payMode) {
        return payMode.getPrice(this);
    }
}

step3 新增支付方式,购物卡,新增实现类,不需要改变顶层结构

  • ShoppingCart
public class ShoppingCart implements PayMode {
    
    public Integer getPrice(Fruit fruit) {
        if (fruit == null) {
            throw new IllegalArgumentException();
        }
        if (fruit instanceof Apple) {
            return getApplePrice((Apple) fruit);
        } else if (fruit instanceof Peach) {
            return getPeachPrice((Peach) fruit);
        } else if (fruit instanceof Watermelon) {
            return getWatermelonPrice((Watermelon) fruit);
        } else {
            throw new IllegalArgumentException();
        }
    }
    
    private Integer getApplePrice(Apple fruit) {
        if (fruit.getCount() > 2) {
            return fruit.getBasePrice() * fruit.getCount() * 0.8;
        } 
        return fruit.getBasePrice() * fruit.getCount();
    }
    
    public Integer getPeachPrice(Peach fruit) {
        if (peach.getCount() > 3) {
            return fruit.getBasePrice() * fruit.getCount() * 0.5;
        }
        return fruit.getBasePrice() * fruit.getCount();
    }
    
    public Integer getWatermelonPrice(Watermelon peach) {
        return fruit.getBasePrice() * fruit.getCount();
    }
}

迭代器模式

概念

  • 遍历一组相同对象的时候,和for循环一致,对比for循环的好处就是,在遍历的时候,能够更加快速和便捷的支持不同方式的遍历

应用场景

  • 同上

UML

迭代器模式.png

Coding

  • ItemIterator
public interface ItemIterator <E> {

    public boolean hasNext();

    public E next();
}
  • Item
@Data
abstract class Item {

    protected ItemType itemType;

    protected String name;

    public Item(ItemType itemType, String name) {
        this.itemType = itemType;
        this.name = name;
    }

}
  • ItemType
public enum ItemType {
    FRUIT,CLOTH,ELECTRIC,MEAT
}
  • ItemCollection
public class ItemCollection {

    private List<Item> itemList = Lists.newArrayList();

    public void add(Item item) {
        itemList.add(item);
    }

    public void remove(Integer index) {
        itemList.remove(index);
    }


    public ItemIterator<Item> getIterator(ItemType itemType) {
        return new ItemIteratorImpl(itemList, itemType);
    }

    private class ItemIteratorImpl implements ItemIterator<Item> {

        private List<Item> items;

        private Integer position = 0;

        private ItemType itemType;

        public ItemIteratorImpl(List<Item> items, ItemType itemType) {
            this.itemType = itemType;
            this.items = items.stream().filter(item -> this.itemType == item.getItemType()).collect(Collectors.toList());;
        }

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

        @Override
        public Item next() {
            Item item = itemList.get(position);
            position++;
            return item;
        }
    }

}

状态模式

概念

  • 类对象的行为基于状态的改变而改变

应用场景

  • 场景假设:有一个人PersonContext,有两个状态,饥饿Hungry和饱腹Full两个状态,对应两个不同的行为。
    • 方案一:PersonContext持有当前状态,并输出对应行为,PersonContext需要对当前状态做if判断,后续增加状态会持续的改动PersonContext
    • 方案二:PersonContext持有当前状态,行为输出托管给对应状态,即状态模式。好处是将PersonContext与对应的行为解耦,增加扩展性,后续不论增加了多少个状态,PersonContext都可以保持顶层设计不变

UML

状态模式.png

Coding

  • State
public interface State {

    public String getState();
    
    public void doAction();
}
  • Hungry
public class Hungry implements State {

    public String getState() {
        return "Hungry";
    }
    
    public void doAction() {
        System.out.println("Choose food");
    }
}
  • Full
public class Full implements State {

    public String getState() {
        return "Full";
    }
    
    public void doAction() {
        System.out.println("Go Home");
    }
}
  • PersonContext
public class PersonContext {
    private State state;
    
     public String getState() {
        return state.getState();
    }
    
    public void doAction() {
        state.doAction();
    } 

}

命令模式

概念

  • 一切request-response model的解耦都可以考虑命令模式

应用场景

  • 著名case:Runnable

UML

  • 其实invoker不是整个模式中的一部分,invoker只是一个命令触发的逻辑,实际意义并不大 命令模式.png

Code

  • Receiver
public interface Receiver {

    void receive(Command command);
}
  • Command (这里换成了抽象类)
public abstract class Command {

    protected Receiver reciever;

    public Command(Receiver reciever) {
        this.reciever = reciever;
    }

    void execute() {
        this.reciever.receive(this);
    }
}
  • Invoker
public interface Invoker {

    void setCommand(Command command);

    void execute();

}
  • ReceiverImpl
public class ReceiverImpl implements Receiver {

    @Override
    public void receive(Command command) {
        if (command instanceof StartCommand) {
            System.out.println("receive command -> start");
        } else if (command instanceof EndCommand) {
            System.out.println("receive command -> end");
        } else {
            throw new IllegalArgumentException();
        }
    }
}
  • StartCommand
public class StartCommand extends Command {

    public StartCommand(Receiver reciever) {
        super(reciever);
    }
}
  • EndCommand
public class EndCommand extends Command {

    public EndCommand(Receiver reciever) {
        super(reciever);
    }
}
  • InvokerImpl
public class InvokerImpl implements Invoker {

    private Command command;

    @Override
    public void setCommand(Command command) {
        this.command = command;
    }

    @Override
    public void execute() {
        this.command.execute();
    }
}
  • Demo
public class Demo {

    public static void main(String[] args) {
        Receiver reciever = new ReceiverImpl();
        Command start = new StartCommand(reciever);
        Command end = new EndCommand(reciever);
        Invoker invoker = new InvokerImpl();

        invoker.setCommand(start);
        invoker.execute();

        invoker.setCommand(end);
        invoker.execute();
    }
}

观察者模式

概念

  • 当一个对象发生变更的时候,另外一组对象需要收到变更消息并且自动更新的场景

应用场景

  • case: javax.servlet.http.HttpSessionAttributeListener

UML

观察者模式.png

Code

  • Observer
public interface Observer {

    public void setSubject(String subject);

    public void reciveMsg();
}
  • Subject
public interface Subject {

    public void register(Observer observer);

    public void unregister(Observer observer);

    public void notifyObservers();
}
  • 策略模式
  • 责任链
  • 中介者模式