浅析设计模式(3/3) - 行为型模式

发布于:2022-12-15 ⋅ 阅读:(515) ⋅ 点赞:(0)

责任链模式

目的:以满足单一职责和开闭原则的方式实现需求的处理调用

优点:

1. 低耦合:请求 发送者 和 处理者 解耦,发送者 只需要将请求发送到责任链即可。

2. 扩展性强:满足开闭原则,根据请求,可以加入新的处理类。

3. 灵活性强:可以动态改变责任链的成员处理方式,或者在职责链的位置。

缺点:

1. 不能保证请求一定被处理,最好在末端还不能处理时进行提示

2. 职责链过程会影响系统性能

3. 增加了客户端的复杂性

代码模拟:

1. 定义一个处理成员的超类

public abstract class Approver {

    Approver approver;//下一个处理者

    String name;

    public Approver(String name) {
        this.name = name;
    }

    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    //处理请求的方法
    public abstract void processRequest(PurchaseRequest purchaseRequest);
}

2.定义三个处理者对象继承超类

public class DepartmentApprover extends Approver{

    public DepartmentApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() <= 5000){
            System.out.println("请求编号id = " + purchaseRequest.getId() + "   " + this.name);
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
public class CollegeApprover extends Approver {

    public CollegeApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if (purchaseRequest.getPrice() > 5000 && purchaseRequest.getPrice() <= 10000) {
            System.out.println("请求编号id = " + purchaseRequest.getId() + "   " + this.name);
        } else {
            approver.processRequest(purchaseRequest);
        }
    }
}
public class SchoolMasterApprover extends Approver{
    public SchoolMasterApprover(String name) {
        super(name);
    }

    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() > 10000){
            System.out.println("请求编号id = " + purchaseRequest.getId() + "   " + this.name);
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
}

3. 定义请求类,模拟一种请求

public class PurchaseRequest {

    private int type = 0;

    private float price = 0.0f;

    private int id = 0;

    public PurchaseRequest(int type, float price, int id) {
        this.type = type;
        this.price = price;
        this.id = id;
    }

    public int getType() {
        return type;
    }

    public void setType(int type) {
        this.type = type;
    }

    public float getPrice() {
        return price;
    }

    public void setPrice(float price) {
        this.price = price;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }
}

4.客户端构建职责链,确保请求一定能被处理,并将三个处理者类形成闭环,这样随便调用一个处理者都可以实现请求的处理

public class Client {
    public static void main(String[] args) {

        PurchaseRequest purchaseRequest = new PurchaseRequest(1, 6000, 1);

        DepartmentApprover rosmontiss = new DepartmentApprover("Rosmontiss");
        CollegeApprover goldenGlow = new CollegeApprover("GoldenGlow");
        SchoolMasterApprover amiya = new SchoolMasterApprover("Amiya");
        
        rosmontiss.setApprover(goldenGlow);
        goldenGlow.setApprover(amiya);
        amiya.setApprover(rosmontiss);

        amiya.processRequest(purchaseRequest);
    }
}

命令模式

目的:将拥有一类职责的对象封装成类,命令对象的唯一职责就是通过execute ()去调用方法,方法调用的·封装,使得我们能更好地对调用进行排队、撤销、处理

优点:

1. 请求者 和 实现者 解耦

2. 拓展性强,增删命令方便

3. 灵活性强,可以实现宏命令

缺点:

1. 系统复杂性高

代码模拟:

组成:

Invoker: 调用者角色

Command: 命令角色,所有命令均在此申明,可以是接口或者抽象类

Receiver: 接收者,处理如何执行一个请求相关操作

ConcreteCommand: 接收一个Receiver和一个动作,调用Receiver对应操作,实现execute

  1. 编写命令接口,子类应实现该命令

    public interface Cammand {
    ​
        public void execute();
        public void undo();
    }
  2. 编写子类具体命令的实现,在命令中聚合子类对象

    public class LightOnCommand implements Cammand{
    ​
        LightRecevier light;
    ​
        public LightOnCommand(LightRecevier light) {
            this.light = light;
        }
    ​
        @Override
        public void execute() {
            light.on();
        }
    ​
        @Override
        public void undo() {
            light.off();
        }
    }
    public class LightOffCommand implements Cammand{
    ​
        LightRecevier light;
    ​
        public LightOffCommand(LightRecevier light) {
            this.light = light;
        }
    ​
    ​
        @Override
        public void execute() {
            light.off();
        }
    ​
        @Override
        public void undo() {
            light.on();
        }
    }
  3. 子类将作为Receiver: 接收者,处理如何执行一个请求相关操作

    public class LightRecevier {
        public void on(){
            System.out.println("电灯打开了...");
        }
        public void off(){
            System.out.println("电灯关闭了...");
        }
    }
  4. 编写一个空命令的实现,这样初始化不许判断命令是否为空✅✅

    //空执行用于初始化每个按钮,当调用空命令时,对象什么都不做,这种设计模式可以省去对空命令的判断
    public class NoCommand implements Cammand{
        @Override
        public void execute() {
        }
        @Override
        public void undo() {
        }
    }
  5. 编写控制类,聚合各种命令,也是客户端要操作的核心类

    public class RemoteController {
    ​
        Cammand[] onCommands;
        Cammand[] offCommands;
        //执行撤销的命令
        Cammand undoCommand;
    ​
        public RemoteController(){
            onCommands = new Cammand[5];
            offCommands = new Cammand[5];
    ​
            for (int i = 0; i < 5; i++) {
                onCommands[i] = new NoCommand();
                offCommands[i] = new NoCommand();
            }
        }
    ​
        public void setCommand(int num,Cammand onCommand,Cammand offCommand){
            onCommands[num] = onCommand;
            offCommands[num] = offCommand;
        }
    ​
        public void onButtonWasPushed(int num){
            onCommands[num].execute();
            undoCommand = onCommands[num];
        }
    ​
        public void offButtonWasPushed(int num){
            offCommands[num].execute();
            undoCommand = onCommands[num];
        }
    ​
        public void undoButtonWasPushed(){
            undoCommand.undo();
        }
    }
  6. 测试

    public class Client {
        public static void main(String[] args) {
    ​
            RemoteController remoteController = new RemoteController();
    ​
            LightRecevier light = new LightRecevier();
    ​
            remoteController.setCommand(0,new LightOnCommand(light),new LightOffCommand(light));
    ​
            remoteController.onButtonWasPushed(0);
            remoteController.undoButtonWasPushed();
    ​
        }
    }



     

解释器模式

在解释器模式中,我们将不可拆分的最小单元称之为终结表达式,可以被拆分的表达式称之为非终结表达式。

该模式地完整过程十分复杂,实际开发中也几乎无需自定义解释器的情况,我们常见的正则表达式就是解释器模式的一种实现,这里不做过多赘述。

迭代器模式

目的:提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。(引用自设计模式一书)

优点:

1. 不要暴露内部细节,即可访问各个元素,可以有效防止外部对数据进行篡改

缺点:

1. 需要实现Iterator接口方法,并编写对应逻辑

代码模拟:

1. 创建学院超类,专业系。

public interface College {

    public String getName();

    public void addDepartment(String name,String des);

    public Iterator createIterator();
}
public class Department {

    private String name;
    private String des;

    public Department(String name, String des) {
        this.name = name;
        this.des = des;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDes() {
        return des;
    }

    public void setDes(String des) {
        this.des = des;
    }

    @Override
    public String toString() {
        return "Department{" +
                "name='" + name + '\'' +
                ", des='" + des + '\'' +
                '}';
    }
}


2.创建具体学院实现类,并提供数组,聚合各个专业系,这里为了方便测试。直接在构造器进行的专业初始化。

public class ComputerCollege implements College{

    Department[] departments;
    int numOfDepartment = 5 ;//保存当前数组对象个数

    public ComputerCollege() {
        this.departments = new Department[5];
        addDepartment("java1","java1");
        addDepartment("java2","java2");
        addDepartment("java3","java3");
        addDepartment("java4","java4");
        addDepartment("java5","java5");
    }

    @Override
    public String getName() {
        return "计算机学院";
    }

    @Override
    public void addDepartment(String name, String des) {
        Department department = new Department(name, des);
        departments[numOfDepartment] = department;
        numOfDepartment += 1;
    }

    @Override
    public Iterator createIterator() {
        return new ComputerCollegeIterator(departments);
    }

}

3.创建该学院对应的构造器,实现Iterator接口,聚合需要遍历的属性,并每次对开始遍历的序号置零,即position=0。

public class ComputerCollegeIterator implements Iterator {

    Department[] departments;
    int position = 0;//遍历的位置

    public ComputerCollegeIterator(Department[] departments) {
        this.departments = departments;
    }

    //判断是否还有下一个元素
    @Override
    public boolean hasNext() {
        if(position >= departments.length || departments[position] == null){
            return false;
        }
        return true;
    }

    @Override
    public Object next() {
        Department department = departments[position];
        position += 1;
        return department;
    }

    @Override
    public void remove() {

    }
}

4.测试,创建实例,获取迭代器,通过迭代器进行遍历即可。


public class Client {

    public static void main(String[] args) {
        ComputerCollege computerCollege = new ComputerCollege();
        Iterator iterator = computerCollege.createIterator();
        while (iterator.hasNext()){
            String s = iterator.next().toString();
            System.out.println(s);
        }
    }
}

中介者模式

目的:将对象之间的操作交给中介对象进行代理执行,简单来说,就是将多对多的关系,简化为多对一,一对多的关系。设计模式种时这样描述的:定义一个中介对象来封装一系列对象之间的交互,使原有对象之间的耦合松散,且可以独立地改变它们之间的交互。

优点:

1. 无需关心多个对象的交互,只需要交给中介类进行处理即可

缺点:

1.随着关系增多,中介类由于是对所有类进行协调处理,可能会导致其变成超级类

代码模拟

1.建造抽象中介类,并编写实体类具体实现

public abstract class Mediator {
    public abstract void Register(Emp emp);

    public abstract void GetMessage(String empName,int doNum);
}
public class ConcreteMediator extends Mediator{
    Map<String,Emp> emps = new HashMap<>();

    public ConcreteMediator(Map<String, Emp> emps) {
        this.emps = emps;
    }

    public ConcreteMediator() {
    }

    @Override
    public void Register(Emp emp) {
        emps.put(emp.getName(),emp);
    }

    @Override
    public void GetMessage(String name, int doNum) {
        Emp emp = emps.get(name);
        switch (doNum){
            case 1:
                emp.Work1();
                break;
            case 2:
                emp.Work2();
                break;
            default:
                System.out.println("Do nothing...");
        }
    }
}

2.创建需要经由中介代理的抽象类,并实现两个具体的实现类

public abstract class Emp {
    private int id;
    private String name;

    public Emp(int id, String name) {
        this.id = id;
        this.name = name;
    }

    public abstract void Work1();

    public abstract void Work2();

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
public class GoldenGlow extends Emp{
    public GoldenGlow() {
        super(2, "GoldenGlow");
    }
    @Override
    public void Work1() {
        System.out.println(this.getName() + "在制造间");
    }

    @Override
    public void Work2() {
        System.out.println(this.getName() + "在休息室");
    }
}
public class Rosmontiss extends Emp{

    public Rosmontiss() {
        super(1,"Rosmontiss");
    }

    @Override
    public void Work1() {
        System.out.println(this.getName() + "在制造间");
    }

    @Override
    public void Work2() {
        System.out.println(this.getName() + "在休息室");
    }
}

3.客户端向中介发送信息,中介即可对对应类下达指令

public class Client {
    public static void main(String[] args) {

        Rosmontiss rosmontiss = new Rosmontiss();
        GoldenGlow goldenGlow = new GoldenGlow();

        Mediator mediator = new ConcreteMediator();
        mediator.Register(goldenGlow);
        mediator.Register(rosmontiss);

        mediator.GetMessage("Rosmontiss",1);
        mediator.GetMessage("GoldenGlow",2);
    }
}

备忘录模式

目的:备份某一状态,便于之后的恢复

优点:

1. 提供了一种状态恢复机制

2. 实现了信息封装,用户无需关系保存细节,只需调用方法

缺点:

1. 消耗资源,成员变量过多会消耗相当一部分内存

代码模拟:

1. 创建目标对象,有攻击力和防御力两个属性

public class GameRole {

    private int vit;
    private int def;

    public GameRole(int vit, int def) {
        this.vit = vit;
        this.def = def;
    }

    public Memento createMemento() {
        return new Memento(vit, def);
    }

    public void recoverGameRoleFromMemento(Memento memento) {
        this.vit = memento.getVit();
        this.def = memento.getDef();
    }

    public void dsiplay() {
        System.out.println(vit + "  " + def);
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }
}

2.创建备份对象,该对象会记录目标对象某一时刻的属性

public class Memento {

    private int vit;
    private int def;

    public Memento(int vit, int def) {
        this.vit = vit;
        this.def = def;
    }

    public int getVit() {
        return vit;
    }

    public void setVit(int vit) {
        this.vit = vit;
    }

    public int getDef() {
        return def;
    }

    public void setDef(int def) {
        this.def = def;
    }
}

3.创建守护者对象,守护者对象用于保存备份对象,方便恢复状态,这里只模拟保存一次的状态,如果需要多次保存,则应该使用链表,Map数组等结构。

//守护者对象
public class Caretaker {
    //只需要保存一次则无需使用数组,若需要对多个保存,则使用hashmap即可
    private Memento memento;

    public Memento getMemento() {
        return memento;
    }

    public void setMemento(Memento memento) {
        this.memento = memento;
    }
}

4.用户备份数据和恢复

public class Client {

    public static void main(String[] args) {
        //创建对象
        GameRole gameRole = new GameRole(100, 50);
        //创建守护者对象
        Caretaker caretaker = new Caretaker();
        //将备份对象放入守护对象中
        caretaker.setMemento(gameRole.createMemento());
        //改变对象数值
        gameRole.setVit(30);
        gameRole.setDef(20);
        //恢复对象数值
        gameRole.recoverGameRoleFromMemento(caretaker.getMemento());
        gameRole.dsiplay();
    }
}

观察者模式(应用较为广泛)

目的:处理一对多的依赖关系,一个对象发送某个事件之后,逐一通知每个观察者

代码模拟:

1. 编写需要观测的数据类,该类为核心类,会用ArrayList聚合观察者对象,并提供注册观察者,删除观察者,提醒方法(当然根据业务需求可以编写更多)

首先是抽象类,指定所有观测数据类都需要实现的基本方法

public interface Subject {

    public void registerObserver(Observer observer);

    public void removeObserver(Observer observer);

    public void notifyObserver();
}

其次是实体类,也是核心类

public class WeatherData implements Subject{
    private float temperature;
    private float pressure;
    private float humidity;

    private ArrayList<Observer> observers;

    public WeatherData(){
        observers = new ArrayList<Observer>();
    }

    public void updateData(float temperature, float pressure, float humidity){
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        this.notifyObserver();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        if(observers.contains(observer)){
            observers.remove(observer);
        }

    }
    @Override
    public void notifyObserver() {
        for (int i = 0; i < observers.size(); i++) {
            observers.get(i).update(this.temperature,this.pressure,this.humidity);
        }
    }
}

2.编写观察者对象接口,以及实体类,观察者类编写跟新方法方便气候数据类在通知时同时进行数据同步。

public interface Observer {
    public void update(float temperature,float pressure,float humidity);
}
//观察者
public class CurrentConditionsOne implements Observer{
    private float temperature;
    private float pressure;
    private float humidity;

    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    public void display(){
        System.out.println("1温度*********" + temperature + "*********");
        System.out.println("1气压*********" + pressure + "*********");
        System.out.println("1湿度*********" + humidity + "*********");
    }
}
public class CurrentConditionsTwo implements Observer{
    private float temperature;
    private float pressure;
    private float humidity;

    public void update(float temperature, float pressure, float humidity) {
        this.temperature = temperature;
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }

    public void display(){
        System.out.println("2温度*********" + temperature + "*********");
        System.out.println("2气压*********" + pressure + "*********");
        System.out.println("2湿度*********" + humidity + "*********");
    }
}

3.客户端调用

public class Client {
    public static void main(String[] args) {
        //创建气象数据对象
        WeatherData weatherData = new WeatherData();

        //模拟两个观察者
        CurrentConditionsOne currentConditionsOne = new CurrentConditionsOne();
        CurrentConditionsTwo currentConditionsTwo = new CurrentConditionsTwo();

        //将观察者注册到该天气对象中
        weatherData.registerObserver(currentConditionsOne);
        weatherData.registerObserver(currentConditionsTwo);

        //更新数据并提醒所有观察者,提醒方法在跟新方法内部被调用
        weatherData.updateData(1,2,3);

    }
}

状态模式(是一种有关多态的设计模式)

目的:减少if-else语句的使用,而是通过不同的状态类进行转换调用。

代码模拟:抽奖系统

四个状态: 可抽奖   不可抽奖   发送奖品  奖品以及发送完毕

1. 定义状态超类,并指定每种状态都需要实现的方法

public abstract class State {
//扣除积分
    public abstract void deductMoney();
//是否中奖
    public abstract boolean raffle();
//发放奖品
    public abstract void dispensePrize();
}

2.不能抽奖状态,最总要的是扣分方法,并在该方法实现状态转换,扣除后即为可抽奖状态,扣除前检测奖品剩余数量,不够则立刻将状态设置为奖品已无

public class NoRaffleState extends State {
    RaffleActivity activity;

    public NoRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }

    @Override
    public void deductMoney() {
        if(activity.getCount() == 0){
            activity.setState(activity.getDispenseOutState());
        }
        System.out.println("扣分50成功");
        activity.setState(activity.getCanRaffleState());

    }

    @Override
    public boolean raffle() {
        System.out.println("需要扣分才能抽奖");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("当前状态不能发放奖品");
    }
}

3.可抽奖状态,通过random进行模拟抽奖,抽中则通过聚合的抽奖活动主类进行状态转换为发放奖品状态返回true,否则返回false。

public class CanRaffleState extends State{

    RaffleActivity activity;

    public CanRaffleState(RaffleActivity activity) {
        this.activity = activity;
    }

    @Override
    public void deductMoney() {
        System.out.println("已经扣除积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("抽奖中...");
        Random random = new Random();
        int num = random.nextInt(2);
        if(num == 0){
            activity.setState(activity.getDispenseState());
            return true;
        }else {
            System.out.println("很遗憾,未抽中奖品...");
            activity.setState(activity.getNoRaffleState());
            return false;
        }
    }

    @Override
    public void dispensePrize() {
        System.out.println("未中奖,不能发放奖品");
    }
}

4.发放奖品状态

public class DispenseState extends State{
    RaffleActivity activity;

    public DispenseState(RaffleActivity activity) {
        this.activity = activity;
    }

    @Override
    public void deductMoney() {
        System.out.println("不能扣除积分");
    }

    @Override
    public boolean raffle() {
        System.out.println("不能抽奖");
        return false;
    }

    @Override
    public void dispensePrize() {
        if(activity.getCount() > 0){
            System.out.println("恭喜中奖!");
            activity.setCount(activity.getCount() - 1);
            activity.setState(activity.getNoRaffleState());
        }else {
            System.out.println("很遗憾,奖品发放完毕");
            activity.setState(activity.getDispenseOutState());
        }
    }
}

4.奖品无库存状态

public class DispenseOutState extends State{
    RaffleActivity activity;

    public DispenseOutState(RaffleActivity activity) {
        this.activity = activity;
    }

    @Override
    public void deductMoney() {
        System.out.println("奖品已无,下次参加");
    }

    @Override
    public boolean raffle() {
        System.out.println("奖品已无,下次参加");
        return false;
    }

    @Override
    public void dispensePrize() {
        System.out.println("奖品已无,下次参加");
    }
}

5.抽奖系统主题类,构造器用于初始化奖品数量,并设置初始状态为不能抽奖状态

public class RaffleActivity {
    //状态情况
    State state = null;
    //奖品数量
    int count = 0;

    State noRaffleState = new NoRaffleState(this);
    State canRaffleState = new CanRaffleState(this);
    State dispenseState = new DispenseState(this);
    State dispenseOutState = new DispenseOutState(this);

    public RaffleActivity(int count) {
        this.state = noRaffleState;//初始就是不能抽奖状态
        this.count = count;
    }

    //扣分
    public void debuctMoney(){
        state.deductMoney();
    }

    //抽奖
    public void raffle(){
        if(state.raffle()){
            state.dispensePrize();
        }
    }

    public State getState() {
        return state;
    }

    public void setState(State state) {
        this.state = state;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }

    public State getNoRaffleState() {
        return noRaffleState;
    }

    public void setNoRaffleState(State noRaffleState) {
        this.noRaffleState = noRaffleState;
    }

    public State getCanRaffleState() {
        return canRaffleState;
    }

    public void setCanRaffleState(State canRaffleState) {
        this.canRaffleState = canRaffleState;
    }

    public State getDispenseState() {
        return dispenseState;
    }

    public void setDispenseState(State dispenseState) {
        this.dispenseState = dispenseState;
    }

    public State getDispenseOutState() {
        return dispenseOutState;
    }

    public void setDispenseOutState(State dispenseOutState) {
        this.dispenseOutState = dispenseOutState;
    }
}

6.客户端进行调用

public class Cilent {

    public static void main(String[] args) {
        RaffleActivity raffleActivity = new RaffleActivity(2);
        for (int i = 0; i < 5; i++) {
            System.out.println("******"+ i + "********");
            raffleActivity.debuctMoney();
            raffleActivity.raffle();
        }
    }
}

模板方法模式

目的:继承一个父类作为模板,某些具体的实现延迟到子类进行

什么是钩子方法?

父类可以定义一个方法,进行默认实现(不进行任何操作,或者返回一个布尔值,控制某个方法不进行实现),子类可以视情况看要不要覆盖它。

1. 创建豆浆制作超类,确定基本模板流程,部分细节创建构造方法延迟给子类使用

public abstract class SolkMaker {

    public void MakeAction(){
        work1();
        if(hookMethod()){
            work2();
        }
        work3();
    }

    public void work1(){
        System.out.println("磨豆子");
    }

    public abstract void work2();

    public boolean hookMethod(){
        return true;
    }

    public void work3(){
        System.out.println("制作豆浆");
    }
}

2.创建不同豆浆种类继承豆浆超类

public class CommonSolk extends SolkMaker {
    @Override
    public void work2() {
    }

    @Override
    public boolean hookMethod() {
        return false;
    }
}
public class BlackSolk extends SolkMaker{
    @Override
    public void work2() {
        System.out.println("加入了黑豆");
    }
}

3.客户端使用

public class Client{
    public static void main(String[] args) {
        SolkMaker commonSolk = new CommonSolk();
        commonSolk.MakeAction();
        SolkMaker blackSolk = new BlackSolk();
        blackSolk.MakeAction();
    }
}

策略模式

目的:将多种相同功能代码进行封装,并提供选择策略给用户,让用户能够根据实际情况自由选择使用哪种模式。

策略模式和状态模式:

1. 策略模式只需要程序选择某种策略完成某件事,强调的是殊途同归

2. 状态模式需要程序在不同状态进行反复切换才能完成某件事,每个状态只能完成整个程序的一部分,需要结合在一起才能完成整件事,强调随势而动。

代码模拟:借助leetcode中策略模式的实现,十分清晰

1.编写枚举类指定不同策略,这样用户可以自由选择

enum SortStrategy {
    BUBBLE_SORT,
    SELECTION_SORT,
    INSERT_SORT
}

2.编写各种实现排序的方法,这里不赘述了,每种方法应该对应枚举类中的内容

3.编写排序接口,使用简单工厂模式编写具体实现类,通过构造器让用户确定使用什么方法进行排序,再调用排序方法进行返回即可实现目标。

interface ISort {
    void sort(int[] arr);
}
class Sort implements ISort {

    private ISort sort;

    Sort(SortStrategy strategy) {
        setStrategy(strategy);
    }

    @Override
    public void sort(int[] arr) {
        sort.sort(arr);
    }

    // 客户端通过此方法设置不同的策略
    public void setStrategy(SortStrategy strategy) {
        switch (strategy) {
            case BUBBLE_SORT:
                sort = new BubbleSort();
                break;
            case SELECTION_SORT:
                sort = new SelectionSort();
                break;
            case INSERT_SORT:
                sort = new InsertSort();
                break;
            default:
                throw new IllegalArgumentException("There's no such strategy yet.");
        }
    }
}

4.测试

public class Client {
    @Test
    public void test() {
        int[] arr = new int[]{6, 1, 2, 3, 5, 4};
        Sort sort = new Sort(SortStrategy.BUBBLE_SORT);
        // 可以通过选择不同的策略完成排序
        // sort.setStrategy(SortStrategy.SELECTION_SORT);
        // sort.setStrategy(SortStrategy.INSERT_SORT);
        sort.sort(arr);
        // 输出 [1, 2, 3, 4, 5, 6]
        System.out.println(Arrays.toString(arr));
    }
}


链接:https://leetcode.cn/leetbook/read/design-patterns/9e2v65/
来源:力扣(LeetCode)
 

访问者模式

目的:将数据结构和数据操作进行分离

什么是双分派:

 在选择一个方法的时候,不仅仅要根据消息接收者(receiver) 的运行时型别(Run time type),还要根据参数的运行时型别(Run time type)

代码模拟

1.编写行为超类

public abstract class Action {

    public abstract void getManResult(Man man);

    public abstract void getWomanResult(Woman woman);
}

2.编写成功和失败两种行为评论

public class Faild extends Action{
    @Override
    public void getManResult(Man man) {
        System.out.println("男人评价失败");
    }

    @Override
    public void getWomanResult(Woman woman) {
        System.out.println("女人评价失败");
    }
}
public class Success extends Action{
    @Override
    public void getManResult(Man man) {
        System.out.println("男人评价成功");
    }

    @Override
    public void getWomanResult(Woman woman) {
        System.out.println("女人评价成功");
    }
}

3.编写评价人超类

public abstract class Person {
    public abstract void accept(Action action);
}

4.编写不同类型的群体,并接收行为类

public class Man extends Person{
    @Override
    public void accept(Action action) {
        action.getManResult(this);
    }
}
//双分派
public class Woman extends Person{
    @Override
    public void accept(Action action) {
        action.getWomanResult(this);
    }
}

5.编写数据结构,来操作不同群体的评价内容

//数据结构,管理了很多人
public class ObjectStructure {

    private List<Person> persons = new LinkedList<>();

    public void attach(Person person){
        persons.add(person);
    }

    public void detach(Person person){
        persons.remove(person);
    }

    public void display(Action action){
        for (Person person:persons){
            person.accept(action);
        }
    }
}

6.客户端调用

public class Client {

    public static void main(String[] args) {
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.attach(new Man());
        objectStructure.attach(new Woman());

        Success success = new Success();
        objectStructure.display(success);
    }
}

本文含有隐藏内容,请 开通VIP 后查看

网站公告

今日签到

点亮在社区的每一天
去签到