设计模式(2)行为型模式和七大原则

news2024/12/26 14:37:02

1、目标

本文的主要目标是学习设计模式的行为型模式并举例说明

2、行为型模式

2.1 观察者模式(Observer)

观察者模式是对象之间存在一对多的依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新,这里的对象指的是Observable目标,依赖目标的对象是Observer观察者,Observer观察者必须调用addObserver方法将Observer观察者注册到Observable目标的容器中,Observable目标监听到事件发生会调用notify方法通知所有的Observer观察者自动更新,观察者模式又叫做发布订阅模式,它的优点是如果新增一个功能监听事件发生,可以创建一个新的Observer观察者,不需要修改Observable目标,耦合性小

需求:用户点击页面会先查询消费者的地址然后展示欢迎页
分析:在点击页面的代码前后加上这两个逻辑,硬编码,如果不同公司的用户点击页面的行为不一样呢

优化思路:采用观察者模式,定义Observer接口,每次添加一个逻辑会创建一个观察者对象,观察者对象需要先注册到Customer对象中的容器,然后调用notify方法会发布消息会循环调用每个观察者对象的update方法,Java提供了Observer观察者对象和Observable目标

程序:

public class ObservableFactory {

    public void clickPage(Customer customer, List<Observer> observerList) {
        for (Observer observer : observerList) {
            customer.addObserver(observer);
        }
        customer.clickPage();
    }

    public class Customer extends Observable {
        // 用户点击页面,会查询消费者的地址和展示欢迎邮件
        public void clickPage() {
            // 必须先设置changed=true才会循环调用Observer的update方法
            // Observable类的setChanged方法是protected只能在这个包下或者子类调用setChanged方法,
            // 每个业务对变化的定义不同,因此它是由子类判断是否变化
            super.setChanged();
            super.notifyObservers();
        }
    }

    public class WelcomeLetter implements Observer {
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("观察者Observer WelcomLetter向目标 " + o + " 发送一个欢迎信");
        }
    }

    public class AddVerify implements Observer {
        @Override
        public void update(Observable o, Object arg) {
            System.out.println("观察者Observer AddVerify向目标 " + o + " 发送一个验证消费者的地址");
        }
    }

}

Java包含了观察者模式的类,Observer类是观察者,Observable类是目标

创建WelcomeLetter、AddVerify两个Observer观察者对象,重写update方法

创建Customer类,继承Observable类,创建clickPage方法,当用户点击页面会先调用setChanged方法然后调用notifyObservers方法通知所有的观察者对象

public interface Observer {
    void update(Observable o, Object arg);
}

Observer接口包含update方法,入参是Observable目标和参数arg

public class Observable {
    private boolean changed = false;
    private Vector<Observer> obs;

    public Observable() {
        obs = new Vector<>();
    }

    public synchronized void addObserver(Observer o) {
        if (o == null)
            throw new NullPointerException();
        if (!obs.contains(o)) {
            obs.addElement(o);
        }
    }

    public synchronized void deleteObserver(Observer o) {
        obs.removeElement(o);
    }

    public void notifyObservers() {
        notifyObservers(null);
    }

    public void notifyObservers(Object arg) {
        Object[] arrLocal;

        synchronized (this) {
            if (!changed)
                return;
            arrLocal = obs.toArray();
            clearChanged();
        }

        for (int i = arrLocal.length-1; i>=0; i--)
            ((Observer)arrLocal[i]).update(this, arg);
    }

    public synchronized void deleteObservers() {
        obs.removeAllElements();
    }

    protected synchronized void setChanged() {
        changed = true;
    }

    protected synchronized void clearChanged() {
        changed = false;
    }

    public synchronized boolean hasChanged() {
        return changed;
    }

    public synchronized int countObservers() {
        return obs.size();
    }
}

Observable类包含changed表示是否变化的标志和obs这个Vector容器,它保存了Observer集合,addObserver方法可以将Observer观察者对象添加到Vector容器中

notifyObservers方法会先判断changed必须是true才会复制Vector容器的元素到一个数组中,然后从后向前逆序遍历数组并调用Observer观察者对象的update方法,逆序是因为防止并发场景,如果正序遍历在循环遍历的时候某个观察者对象从Vector容器中取消了会导致数组的索引变化了,导致并发修改异常

setChanged方法是protected类型的,因为每个业务都变化的定义都不相同,因此可以创建一个子类继承Observable类自己定义什么时候需要调用setChanged方法表示数据变化了

public class TaskController {
    @Test
    public void f2() {
        ObservableFactory observableFactory = new ObservableFactory();
        ObservableFactory.Customer customer = observableFactory.new Customer();
        ObservableFactory.WelcomeLetter welcomeLetter = observableFactory.new WelcomeLetter();
        ObservableFactory.AddVerify addVerify = observableFactory.new AddVerify();
        List<Observer> list = new ArrayList<>(2);
        list.add(welcomeLetter);
        list.add(addVerify);
        observableFactory.clickPage(customer, list);
    }
}

TaskController是创建Customer对象、WelcomeLetter、AddVerify,调用clickPage方法可以发布并且观察者可以得到通知并自动更新

测试结果:

在这里插入图片描述

目标对象发布消息,观察者会得到通知并自动更新

2.2 状态模式(State)

状态模式是对象有多种状态,不同状态之间的变化封装在不同的状态类中,思路是定义一个状态接口和多个状态实现类,每个状态实现类都重写转换到其他状态的方法,最后定义一个活动类,通过map.get得到对应的状态类并调用方法

程序:

public class StateFactory {

    public class Activity {
        private String state;
        private Map<String, ActivityState> map = new HashMap<>();
        public Activity() {
            state = "结束";
            map.put("启动", new ActivityStartedState());
            map.put("暂停", new ActivityResumedState());
            map.put("结束", new ActivityEndedState());
        }
        public void setState(String state) {
            this.state = state;
        }
        public String getState() {
            return state;
        }
        public void startActivity() {
            map.get(state).startActivity(this);
        }
        public void resumeActivity() {
            map.get(state).resumeActivity(this);
        }
        public void endActivity() {
            map.get(state).endActivity(this);
        }
    }

    public interface ActivityState {
        public abstract void startActivity(Activity activity);
        public abstract void resumeActivity(Activity activity);
        public abstract void endActivity(Activity activity);
    }

    public class ActivityStartedState implements ActivityState {
        @Override
        public void startActivity(Activity activity) {
            System.out.println("活动已经启动了,不能重复启动");
        }
        @Override
        public void resumeActivity(Activity activity) {
            System.out.println("活动暂停");
            activity.setState("暂停");
            System.out.println("state = " + activity.getState());
        }
        @Override
        public void endActivity(Activity activity) {
            System.out.println("活动结束");
            activity.setState("结束");
            System.out.println("state = " + activity.getState());
        }
    }

    public class ActivityResumedState implements ActivityState {
        @Override
        public void startActivity(Activity activity) {
            System.out.println("活动重新启动");
            activity.setState("启动");
            System.out.println("state = " + activity.getState());
        }
        @Override
        public void resumeActivity(Activity activity) {
            System.out.println("活动已经暂停了,不能重复暂停");
        }
        @Override
        public void endActivity(Activity activity) {
            System.out.println("活动结束");
            activity.setState("结束");
            System.out.println("state = " + activity.getState());
        }
    }

    public class ActivityEndedState implements ActivityState {
        @Override
        public void startActivity(Activity activity) {
            System.out.println("活动启动");
            activity.setState("启动");
            System.out.println("state = " + activity.getState());
        }
        @Override
        public void resumeActivity(Activity activity) {
            System.out.println("活动已经结束,不能暂停");
        }
        @Override
        public void endActivity(Activity activity) {
            System.out.println("活动已经结束,不能重复结束");
        }
    }

}

定义一个状态接口和多个状态实现类,每个状态类都重写转换到其他状态的方法,还定义了一个活动类,封装了state状态表示活动的当前状态,封装了一个Map可以存放不同的state和对应的状态对象,通过map.get方法得到状态对象并调用状态对象的方法

@Test
public void f18() {
    StateFactory stateFactory = new StateFactory();
    StateFactory.Activity activity = stateFactory.new Activity();
    activity.startActivity();
    activity.resumeActivity();
    activity.endActivity();
}

创建一个活动对象,活动对象的状态初始化是结束状态,先调用活动对象的start方法可以从结束状态转换到启动状态,然后调用活动对象的resume方法可以从启动状态转换到暂停状态,最后调用活动对象的end方法可以从暂停状态转换到结束状态

测试结果:

在这里插入图片描述

测试结果表明状态模式应用成功,可以正常切换活动状态

2.3 责任链模式(Chain Of Responsibility)

责任链模式是允许多个对象都可以处理请求,会将这些对象连成一个链,直到有一个对象可以处理请求为止,思路是定义一个抽象类,组合一个对象因为每个对象都持有下一个对象的引用

程序:

public class LoggerFactory {

    abstract public class Logger {
        protected Logger nextLogger;
        public void setNextLogger(Logger nextLogger) {
            this.nextLogger = nextLogger;
        }
        abstract public void log(int logLevel);
    }

    public class DebugLogger extends Logger {
        @Override
        public void log(int logLevel) {
            if(logLevel == 0) {
                System.out.println("打印debug日志");
            } else {
                nextLogger.log(logLevel);
            }
        }
    }

    public class InfoLogger extends Logger {
        @Override
        public void log(int logLevel) {
            if(logLevel == 1) {
                System.out.println("打印info日志");
            } else {
                nextLogger.log(logLevel);
            }
        }
    }

    public class ErrorLogger extends Logger {
        @Override
        public void log(int logLevel) {
            if(logLevel == 2) {
                System.out.println("打印error日志");
            } else {
                nextLogger.log(logLevel);
            }
        }
    }

}

定义一个抽象类,它组合了下一个对象,抽象方法log方法用来打印日志,多个继承类可以重写log方法,如果条件不满足就调用下一个对象的log方法

@Test
public void f19() {
    LoggerFactory loggerFactory = new LoggerFactory();
    LoggerFactory.DebugLogger debugLogger = loggerFactory.new DebugLogger();
    LoggerFactory.InfoLogger infoLogger = loggerFactory.new InfoLogger();
    LoggerFactory.ErrorLogger errorLogger = loggerFactory.new ErrorLogger();
    debugLogger.setNextLogger(infoLogger);
    infoLogger.setNextLogger(errorLogger);
    debugLogger.log(2);
    debugLogger.log(1);
    debugLogger.log(0);
}

创建一个对象链,如果这个对象满足条件会打印日志,如果不满足条件会沿着对象链调用下一个对象的打印日志方法

输出结果:

在这里插入图片描述

第一个方法打印日志是error,第二个方法打印日志是info,第三个方法打印日志是debug

2.4 策略模式(Strategy)

策略模式是定义多个算法,它们可以相互替换,定义一个抽象类和多个实现类,寻找可变的参数并封装到这个抽象类中

需求:处理订单计算不同国家的税

分析:直接if else,硬编码,如果情况很多会有很多if else

优化思路:计算税用一个抽象类,定义一个抽象方法,多个实现类重写这个方法,就可以计算不同国家的税

程序:

public class SalesOrder {

    // CalcTax作为入参
    public void process(CalcTax calcTax, int num, double price) {
        double total = calcTax.taxAmount(num, price);
        System.out.println(calcTax.getClass() + "  total = " + total);
    }

    // 成员内部类
    public abstract class CalcTax {
        abstract public double taxAmount(int num, double price);
    }

    // 成员内部类
    public class USTax extends CalcTax {
        @Override
        public double taxAmount(int num, double price) {
            return num * price * 2;
        }
    }

    // 成员内部类
    public class CanTax extends CalcTax {
        @Override
        public double taxAmount(int num, double price) {
            return num * price * 1.5;
        }
    }

}

CalcTax抽象类和继承类都封装在SalesOrder类中,CalcTax抽象类作为SalesOrder类的process方法的入参

public class TaskController {
    @Test
    public void f1() {
        SalesOrder salesOrder = new SalesOrder();
        SalesOrder.USTax usTax = salesOrder.new USTax();
        salesOrder.process(usTax, 2, 15);
        SalesOrder.CanTax canTax = salesOrder.new CanTax();
        salesOrder.process(canTax, 2, 15);
    }
}

TaskController类的f1方法创建SalesOrder类的对象和成员内部类的对象USTax和CanTax,最后SalesOrder对象调用process方法,入参传入成员内部类的对象USTax和CanTax

测试结果是:

在这里插入图片描述

2.5 模板方法模式(Template Method)

模板方法模式是定义算法的骨架,将一些步骤推迟到子类中实现,父类定义多个抽象方法,子类实现这些抽象方法,父类还定义了一个普通方法,这个普通方法封装了这些抽象方法

需求:不同数据库连接数据库并且查询数据库的数据

分析:对每个数据库都创建一个方法,重复代码多

优化思路:创建一个抽象类,封装了连接数据库的抽象方法和查询数据库的抽象方法,还封装了一个普通方法,这个普通方法封装了这些抽象方法,每个数据库都创建一个实现类,重写连接数据库的抽象方法和查询数据库的抽象方法

程序:

public class QueryDBFactory {

    public void doQuery(QueryDBTemplate queryDBTemplate) {
        queryDBTemplate.doQuery();
    }

    abstract public class QueryDBTemplate {
        abstract public void getConnection();
        abstract public void selectFromDB();
        public void doQuery() {
            getConnection();
            selectFromDB();
        }
    }

    public class MysqlDB extends QueryDBTemplate {
        @Override
        public void getConnection() {
            System.out.println("MysqlDB获取连接");
        }
        @Override
        public void selectFromDB() {
            System.out.println("MysqlDB查询数据库的数据");
        }
    }

    public class OracleDB extends QueryDBTemplate {
        @Override
        public void getConnection() {
            System.out.println("OracleDB获取连接");
        }
        @Override
        public void selectFromDB() {
            System.out.println("OracleDB查询数据库的数据");
        }
    }

}

定义一个抽象类QueryDBTemplate,定义抽象方法getConnection和selectFromDB,抽象类中还定义了一个普通方法doQuery,doQuery方法封装了这两个抽象方法,可以减少重复代码

创建两个子类分别表示不同的数据库,每个子类都重写这两个抽象方法

public class TaskController {
    @Test
    public void f3() {
        QueryDBFactory queryDBFactory = new QueryDBFactory();
        QueryDBFactory.QueryDBTemplate queryDBTemplate = queryDBFactory.new MysqlDB();
        queryDBFactory.doQuery(queryDBTemplate);
        System.out.println("========================================");
        queryDBTemplate = queryDBFactory.new OracleDB();
        queryDBFactory.doQuery(queryDBTemplate);
    }
}

分别采用Mysql和Oracle的子类查询数据库

测试结果:

在这里插入图片描述

模板模式在抽象类中定义普通方法是每个数据库都先获取连接然后查询数据库的数据

2.6 命令模式(Command)

命令模式是将请求和执行解耦合,使得请求不知道执行的具体实现,用于封装操作并延迟执行这些操作,思路是创建一个命令接口,创建多个命令类实现这个接口,命令类中组合了请求对象

程序:

public class CommandFactory {

    public interface Command {
        void execute();
    }

    public class Person {
        public void work() {
            System.out.println("工作");
        }
        public void sport() {
            System.out.println("运动");
        }
        public void sleep() {
            System.out.println("睡觉");
        }
    }

    public class WorkCommand implements Command {
        private Person person;
        public WorkCommand(Person person) {
            this.person = person;
        }
        @Override
        public void execute() {
            person.work();
        }
    }

    public class SportCommand implements Command {
        private Person person;
        public SportCommand(Person person) {
            this.person = person;
        }
        @Override
        public void execute() {
            person.sport();
        }
    }

    public class SleepCommand implements Command {
        private Person person;
        public SleepCommand(Person person) {
            this.person = person;
        }
        @Override
        public void execute() {
            person.sleep();
        }
    }

}

创建一个命令接口Command,创建多个实现类作为命令,组合了Person对象

@Test
public void f13() {
    CommandFactory commandFactory = new CommandFactory();
    CommandFactory.Person person = commandFactory.new Person();
    CommandFactory.WorkCommand workCommand = commandFactory.new WorkCommand(person);
    CommandFactory.SportCommand sportCommand = commandFactory.new SportCommand(person);
    CommandFactory.SleepCommand sleepCommand = commandFactory.new SleepCommand(person);
    workCommand.execute();
    sportCommand.execute();
    sleepCommand.execute();
}

测试结果:

在这里插入图片描述

命令模式会创建多个对象,然后执行

2.7 迭代器模式(Iterator)

迭代器模式是顺序遍历数组的所有元素,不用关心数组的实现,可以将遍历和数组的实现解耦合

程序:

public class IteratorFactory {

    public interface Iterator {
        public boolean hasNext();
        public Object next();
    }

    public class Hobbies implements Iterator {
        private String[] arr;
        private int index;
        public Hobbies(String[] arr) {
            this.arr = arr;
            index = 0;
        }
        @Override
        public boolean hasNext() {
            return index < arr.length;
        }
        @Override
        public Object next() {
            return arr[index++];
        }
    }

}

通过迭代器遍历数组,需要先创建迭代器接口,创建一个类实现迭代器接口

@Test
public void f14() {
    IteratorFactory iteratorFactory = new IteratorFactory();
    String[] arr = new String[]{"a","b","c","d","e"};
    IteratorFactory.Hobbies hobbies = iteratorFactory.new Hobbies(arr);
    while (hobbies.hasNext()) {
        System.out.println(hobbies.next());
    }
}

通过迭代器对象遍历数组,可以将遍历和数组的实现解耦合

测试结果:

在这里插入图片描述

迭代器模式可以顺序遍历数组中的所有元素

2.8 中介者模式(Mediator)

中介者模式是用一个中介者对象封装对象之间的交互,可以降低对象之间的耦合

程序:

public class MediatorFactory {

    // 中介者
    public class QQ {
        public void sendMsg(User sender, User receiver, String msg) {
            System.out.println(sender.getName() + " send msg: " + msg + " to " + receiver.getName());
        }
    }

    public class User {
        private String name;
        private QQ qq;
        public User(String name, QQ qq) {
            this.name = name;
            this.qq = qq;
        }
        public String getName() {
            return name;
        }
        // 用户通过QQ中介者发送消息
        public void sendMsg(String msg, User receiver) {
            qq.sendMsg(this, receiver, msg);
        }
    }

}

用户对象之间的交互需要通过QQ这个中介者对象进行交互,因此用户对象应该持有中介者对象QQ

@Test
public void f15() {
    MediatorFactory mediatorFactory = new MediatorFactory();
    MediatorFactory.QQ qq = mediatorFactory.new QQ();
    MediatorFactory.User user01 = mediatorFactory.new User("user01", qq);
    MediatorFactory.User user02 = mediatorFactory.new User("user02", qq);
    user01.sendMsg("hello", user02);
    user02.sendMsg("hi", user01);
}

用户对象之间发送消息必须通过中介者对象QQ

测试结果:

在这里插入图片描述

用户对象发送消息会通过中介者对象QQ

2.9 备忘录模式(Memento)

备忘录模式是在破坏对象封装性的前提下恢复状态,思路是创建备忘录对象来保存对象状态

程序:

public class MementoFactory {

    public class Memento {
        private String state;
        public Memento(String state) {
            this.state = state;
        }
        public String getState() {
            return state;
        }
        public void setState(String state) {
            this.state = state;
        }
    }

    public class Activity {
        private String state;
        public String getState() {
            return state;
        }
        public Memento begin() {
            state = "开始";
            return new Memento(state);
        }
        public Memento resume() {
            state = "暂停";
            return new Memento(state);
        }
        public Memento end() {
            state = "结束";
            return new Memento(state);
        }
        public void restore(Memento memento) {
            state = memento.getState();
        }
    }

}

创建备忘录类Memento,Activity活动类在修改活动状态的时候会返回备忘录对象,通过restore方法可以恢复活动对象的状态

@Test
public void f16() {
    MementoFactory mementoFactory = new MementoFactory();
    MementoFactory.Activity activity = mementoFactory.new Activity();
    MementoFactory.Memento beginMemento = activity.begin();
    MementoFactory.Memento resumeMemento = activity.resume();
    MementoFactory.Memento endMemento = activity.end();
    activity.restore(endMemento);
    System.out.println(activity.getState());
    activity.restore(resumeMemento);
    System.out.println(activity.getState());
    activity.restore(beginMemento);
    System.out.println(activity.getState());
}

创建活动对象,创建备忘录对象,通过restore方法可以恢复活动状态

测试结果:

在这里插入图片描述

备忘录模式可以恢复活动状态

2.10 解释器模式(Interpreter)

解释器模式是解释执行语言的表达式,会将每个表达式抽象成一个类,通过组合表达式可以构建复杂的表达式

程序:

public class InterpreterFactory {

    public interface Interpreter {
        int interpreter();
    }

    public class NumberInterpreter implements Interpreter {
        private int num;
        public NumberInterpreter(int num) {
            this.num = num;
        }
        @Override
        public int interpreter() {
            return num;
        }
    }

    public class AddInterpreter implements Interpreter {
        private Interpreter number1;
        private Interpreter number2;
        public AddInterpreter(Interpreter number1, Interpreter number2) {
            this.number1 = number1;
            this.number2 = number2;
        }
        @Override
        public int interpreter() {
            return number1.interpreter() + number2.interpreter();
        }
    }

}

解释器模式会定义一个解释器接口,定义数字解释器和相加操作的解释器,重写interpreter方法

@Test
public void f17() {
    InterpreterFactory interpreterFactory = new InterpreterFactory();
    InterpreterFactory.NumberInterpreter number1 = interpreterFactory.new NumberInterpreter(3);
    InterpreterFactory.NumberInterpreter number2 = interpreterFactory.new NumberInterpreter(6);
    InterpreterFactory.AddInterpreter addInterpreter = interpreterFactory.new AddInterpreter(number1, number2);
    System.out.println(addInterpreter.interpreter());
}

定义两个数字解释器和一个相加操作的解释器,计算相加操作的结果

测试结果:

在这里插入图片描述

解释器模式可以计算多个表达式得到结果

2.11 访问者模式(Visitor)

访问者模式是在不改变元素类的前提下,定义这些元素的操作,将数据结构和操作分离开,使得操作可以独立的变化

程序:

public class VisitorFactory {

    public interface Visitor {
        abstract public void visitElement1(Element1 element1);
        abstract public void visitElement2(Element2 element2);
    }

    public class RealVisitor implements Visitor {
        @Override
        public void visitElement1(Element1 element1) {
            element1.log1();
        }
        @Override
        public void visitElement2(Element2 element2) {
            element2.log2();
        }
    }

    public interface Element {
        void accept(Visitor visitor);
    }

    public class Element1 implements Element {
        @Override
        public void accept(Visitor visitor) {
            visitor.visitElement1(this);
        }
        public void log1() {
            System.out.println("打印元素1的日志");
        }
    }

    public class Element2 implements Element {
        @Override
        public void accept(Visitor visitor) {
            visitor.visitElement2(this);
        }
        public void log2() {
            System.out.println("打印元素2的日志");
        }
    }

}

定义元素,定义访问者接口和实现类

@Test
public void f20() {
    VisitorFactory visitorFactory = new VisitorFactory();
    VisitorFactory.Element1 element1 = visitorFactory.new Element1();
    VisitorFactory.Element2 element2 = visitorFactory.new Element2();
    VisitorFactory.RealVisitor realVisitor = visitorFactory.new RealVisitor();
    element1.accept(realVisitor);
    element2.accept(realVisitor);
}

调用元素的accept方法,可以调用访问者visitor的方法

测试结果:

在这里插入图片描述

3、七大设计原则

设计模式的七大原则是

(1)单一职责原则:一个类只负责一个职责

(2)开闭原则:对扩展开放,对修改关闭

(3)里氏替换原则:子类可以替换父类的方法保证程序运行正常,子类可以实现父类没有的方法完成新增功能,但是子类不应该重写父类的方法

假设有一个父类 Bird 和一个子类 Penguin。假设 Bird 类有一个方法 fly(),表示鸟类能够飞行。如果我们按照里氏替换原则,Penguin 类(企鹅)继承自 Bird,但企鹅是不会飞的
如果我们在 Penguin 类中实现了 fly() 方法,且它要么做得不如 Bird 类中的 fly() 方法好(即不能飞),要么导致错误或异常(例如抛出不适当的异常),则违反了里氏替换原则
正确的做法是将 fly() 方法移除或使其在 Penguin 中不适用,或者将 Penguin 类从 Bird 类中移除,因为企鹅并不符合“可以飞”的行为约定。在这种情况下,我们可能会创建一个 FlyingBird 类来继承自 Bird,而 Penguin 类则从 Bird 类中移除,确保只有那些确实可以飞的鸟类继承 FlyingBird

(4)依赖反转原则:抽象不要依赖细节,细节应该依赖抽象,这里抽象指的是接口和抽象类

(5)接口隔离原则:尽可能将一个接口拆分成多个小接口,客户端不应该依赖它不需要的接口

(6)合成复用原则:尽量使用组合替换继承

(7)迪米特法则:最少知识原则,一个类应该保持对另一个类最小的了解

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2048537.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

京东数据编织

计算引擎是Hbase 中间计算结果的物化【就是存下来】 自动物化 在这里插入图片描述

设计模式在芯片验证中的应用——状态

一、状态模式 状态模式是一种行为设计模式&#xff0c; 让你能在一个对象的内部状态变化时改变其行为&#xff0c; 使其看上去就像改变了自身所属的类一样。 在RTL中可能存在复杂的有限状态机FSM&#xff0c;在任何一个特定状态中&#xff0c; RTL的行为都不相同&#xff0c;…

pip install 遇到ValueError: check_hostname requires server_hostname的解决办法

我需要下载Cython来将py编译成c&#xff0c;结果在pip install的时候报错这个&#xff1a; ERROR: Exception: Traceback (most recent call last):File "F:\Anaconda3\envs\DouyinLive32\lib\site-packages\pip\_internal\cli\base_command.py", line 173, in _mai…

《人类群星闪耀时》

人类群星闪耀时&#xff0c;历史的舞台上&#xff0c;你未尝不是其中一颗。 【拜占庭的沦陷】具备决断力、创新力、执行力的领导者起到关键作用。 【享德尔的复活】人的心力一旦强大&#xff0c;便可创造非凡之事。 【一夜天才】闪耀的星离不开黑夜的衬托。所谓的英雄&#x…

HarmonyOS Developer之生成二维码

qrcode 生成并显示二维码 属性 样式 创建qrcode组件 在pages/index目录下的hml文件中创建一个qrcode组件 HTML <!-- xxx.hml--> <div class"container"><qrcode value"Hello"></qrcode> </div>CSS /* xxx.css */ .cont…

uniapp 微信小程序生成水印图片

效果 源码 <template><view style"overflow: hidden;"><camera device-position"back" flash"auto" class"camera"><cover-view class"text-white padding water-mark"><cover-view class"…

基于JAVA的社团管理系统的设计与实现

TOC springboot270基于JAVA的社团管理系统的设计与实现 第1章 绪论 1.1 课题背景 互联网发展至今&#xff0c;无论是其理论还是技术都已经成熟&#xff0c;而且它广泛参与在社会中的方方面面。它让信息都可以通过网络传播&#xff0c;搭配信息管理工具可以很好地为人们提供…

html+css 实现hover 边框彩色按钮

前言:哈喽,大家好,今天给大家分享html+css 绚丽效果!并提供具体代码帮助大家深入理解,彻底掌握!创作不易,如果能帮助到大家或者给大家一些灵感和启发,欢迎收藏+关注哦 💕 目录 一、效果二、原理解析1.这是一个,hover后按钮边框==变彩色==的效果。每个按钮都是1个but…

matlab关于结构体的创建

网上搜了很多结构体的创建&#xff0c;都是什么student.name student.age,或者struct. 自己摸索了一下&#xff0c;根据你想要创建结构体的格式可以划分以下两类 clear all clcdata [1, 2, 2, 1;2, 1, 1, 3;4, 3, 2, 2];data1 [0, 2, 2, 1;0, 1, 1, 3;4, 3, 0, 2;4, 3, 0, 2…

解锁企业数字化转型的终极指南:《数字时代的敏捷架构》深度解读

在当前数字化浪潮的冲击下&#xff0c;企业面临着前所未有的挑战与机遇。为了解决这一难题&#xff0c;The Open Group 和 AZone 联手推出了《数字时代的敏捷架构》&#xff0c;《数字时代的敏捷架构》汇集了全球顶尖专家的智慧和经验&#xff0c;是企业数字化转型的必读之作。…

【IEEE独立出版】第四届人工智能、虚拟现实与可视化国际学术会议(AIVRV 2024)

第四届人工智能、虚拟现实与可视化国际学术会议&#xff08;AIVRV 2024&#xff09; 2024 4th International Conference on Artificial Intelligence, Virtual Reality and Visualization 会议时间&#xff1a;2024年11月1日-3日 会议地点&#xff1a;中国-南京…

C语言第20天笔记

文件操作 概述 什么是 文件 文件时保存在外存储器上&#xff08;一般代指磁盘&#xff0c;也可以是U盘、移动硬盘等&#xff09;的数据的集合。 文件操作体现在哪几个方面 1. 文件内容的读取 2. 文件内容的写入 数据的读取和写入可被视为针对文件进行输入和输出的操作&a…

函数递归那些事

什么是递归 递归就是函数自己调用自己&#xff0c;而递归的本质其实是一种解决问题的方法。 递归的思想 递归的思想是把复杂问题大事化小的过程。即把一个大型复杂的问题不断的拆分成与原问题相似&#xff0c;但规模较小的子问题&#xff0c;直到子问题不能被拆分&#xff0…

Python学习day16-类与对象

这里写目录标题 类示例 成员方法self关键字 类与对象构造方法其他类内置方法&#xff08;魔术方法&#xff09;_str_符号_Lt_符号le小于等于比较eq比较运算小结 类 在Python中&#xff0c;class&#xff08;类&#xff09;是一种用于创建对象的模板或蓝图。它封装了数据&#…

MySQL9.0安装教程

软件介绍 MySQL是一个关系型数据库管理系统&#xff0c;是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Database Management System&#xff0c;关系数据库管理系统) 应用软件之一。 软件下载 https://pan.qu…

预报名管理系统--论文pf

TOC springboot374预报名管理系统--论文pf 第1章 绪论 1.1选题动因 当前的网络技术&#xff0c;软件技术等都具备成熟的理论基础&#xff0c;市场上也出现各种技术开发的软件&#xff0c;这些软件都被用于各个领域&#xff0c;包括生活和工作的领域。随着电脑和笔记本的广泛…

UI设计:蒸汽波风格页面有啥特征,应用哪些场景?

一、什么是蒸汽波风格 蒸汽波风格&#xff08;Steampunk&#xff09;是一种将19世纪工业时代的技术和想象力与未来科技相结合的艺术和文化流派。它通常描绘了一个类似维多利亚时代的世界&#xff0c;其中蒸汽动力是主要能源&#xff0c;机械装置和复杂的齿轮系统被广泛应用。 …

C#商城源码与.NET技术在电商领域的应用_OctShop

在当今互联网化商业的浪潮中&#xff0c;网上商城成为了企业拓展市场、提升竞争力的重要手段。而 C# 商城源码和.NET 相关的技术在构建高效、稳定、安全的网上商城中发挥着关键作用。OctShop将深入探讨 C# 商城源码、.NET 商城源码、C# 网上商城以及.NET Core 商城源码的特点、…

JavaScript基础(34)_BOM介绍、BOM对象

BOM 浏览器对象模型&#xff0c;BOM可以使我们通过JS来操作浏览器。在BOM中为我们提供了一组对象&#xff0c;用来完成对浏览器的操作。 BOM对象 Window&#xff1a;代表整个浏览器的窗口&#xff0c;同时window也是网页中的全局对象。Navigator&#xff1a;代表当前浏览器的…

VS2022实用调试技巧超详解

文章目录 1. 什么是 bug2. 什么是调试(debug)3. Debug和 Release4.VS调试快捷键4.1 环境准备4.2 调试快捷键 5. 监视和内存观察5.1 监视5.2 内存 6. 调试举例17. 调试举例29. 编程常见错误归类9. 1 编译型错误9.2 链接型错误9. 3 运行时错误 本文章以VS2022为例讲解调试功能&am…