您现在的位置是:主页 > news > 湖北网站建设专家/免费影视软件靠什么赚钱
湖北网站建设专家/免费影视软件靠什么赚钱
admin2025/5/22 10:35:24【news】
简介湖北网站建设专家,免费影视软件靠什么赚钱,ubuntu 装wordpress,wordpress obj cache在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象会接受…
在访问者模式(Visitor Pattern)中,我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象会接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
使用场景
- 对象结构比较稳定,但经常需要在此对象结构上定义新的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而需要避免这些操作“污染”这些对象的类,也不希望在增加新操作时修改这些类。
角色介绍
- Visitor:接口或者抽象类,定义了对每个 Element 访问的行为,它的参数就是被访问的元素,它的方法个数理论上与元素的个数是一样的,因此,访问者模式要求元素的类型要稳定,如果经常添加、移除元素类,必然会导致频繁地修改 Visitor 接口,如果出现这种情况,则说明不适合使用访问者模式。
- ConcreteVisitor:具体的访问者,它需要给出对每一个元素类访问时所产生的具体行为。
- Element:元素接口或者抽象类,它定义了一个接受访问者(accept)的方法,其意义是指每一个元素都要可以被访问者访问。
- ElementA、ElementB:具体的元素类,它提供接受访问的具体实现,而这个具体的实现,通常情况下是使用访问者提供的访问该元素类的方法。
- ObjectStructure:定义当中所提到的对象结构,对象结构是一个抽象表述,它内部管理了元素集合,并且可以迭代这些元素提供访问者访问。
实现
年底,CEO和CTO开始评定员工一年的工作绩效,员工分为工程师和经理,CTO关注工程师的代码量、经理的新产品数量;CEO关注的是工程师的KPI和经理的KPI
由于CEO和CTO对于不同员工的关注点是不一样的,这就需要对不同员工类型进行不同的处理。访问者模式此时可以派上用场了。
第一步、定义元素接口和元素类
Staff 类定义了员工基本信息及一个 accept 方法,accept 方法表示接受访问者的访问,由子类具体实现。Visitor 是个接口,传入不同的实现类,可访问不同的数据。下面看看工程师和经理的代码:
/*** 员工基类*/
public abstract class Staff {public String name; //员工姓名public int kpi; //员工KPIpublic Staff(String name) {this.name = name;kpi = new Random().nextInt(10);}// 核心方法,接受Visitor的访问public abstract void accept(Visitor visitor);
}
/*** 工程师* 考核数据----KPI、代码数量*/
public class Engineer extends Staff {public int codeNum; //一年的代码数量public Engineer(String name) {super(name);codeNum = new Random().nextInt(10 * 10000);}public int getCodeLines() {return codeNum;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
/*** 经理*考核数据----KPI、产品数量*/
public class Manager extends Staff {public int productNum; //一年做的产品数量public Manager(String name) {super(name);productNum = new Random().nextInt(10);}public int getProducts() {return productNum;}@Overridepublic void accept(Visitor visitor) {visitor.visit(this);}
}
第二步、定义访问者接口和具体访问者
首先定义了一个 Visitor 接口,该接口有两个 visit 函数,参数分别是 Engineer、Manager,也就是说对于 Engineer、Manager 的访问会调用两个不同的方法,以此达成区别对待、差异化处理。具体实现类为 CEOVisitor、CTOVisitor类,具体代码如下:
/*** 访问者接口*/
public interface Visitor {// 访问工程师类型void visit(Engineer engineer);// 访问经理类型void visit(Manager manager);
}
/*** CEO访问者*/
public class CEOVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi);}@Overridepublic void visit(Manager manager) {System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi);}
}
/*** CTO访问者*/
public class CTOVisitor implements Visitor {@Overridepublic void visit(Engineer engineer) {System.out.println("工程师: " + engineer.name + ", 代码行数: " + engineer.getCodeLines());}@Overridepublic void visit(Manager manager) {System.out.println("经理: " + manager.name + ", 产品数量: " + manager.getProducts());}
}
在CEO的访问者中,CEO关注工程师的 KPI,经理的 KPI ,通过两个 visitor 方法分别进行处理。如果不使用 Visitor 模式,只通过一个方法进行处理,那么就需要在这个方法中进行判断,然后分别处理,代码大致如下:
/*** 不用访问者模式,则需要大量的 if-else判断* @param visitor*/public void showReport2(Visitor visitor) {if (visitor instanceof CEOVisitor){for (Staff staff : mStaffs) {if (staff instanceof Manager) {Manager manager = (Manager) staff;System.out.println("经理: " + manager.name + ", KPI: " + manager.kpi +", 新产品数量: " + manager.getProducts());} else if (staff instanceof Engineer) {Engineer engineer = (Engineer) staff;System.out.println("工程师: " + engineer.name + ", KPI: " + engineer.kpi);}}}else if (visitor instanceof CTOVisitor){for (Staff staff : mStaffs) {if (staff instanceof Manager) {Manager manager = (Manager) staff;System.out.println("经理: " + manager.name + ", 产品数量: " + manager.getProducts());} else if (staff instanceof Engineer) {Engineer engineer = (Engineer) staff;System.out.println("工程师: " + engineer.name + ", 代码行数: " + engineer.getCodeLines());}}}}
这就导致了 if-else 逻辑的嵌套以及类型的强制转换,难以扩展和维护,当类型较多时,这个 ReportUtil 就会很复杂。而使用 Visitor 模式,通过同一个函数对不同对元素类型进行相应对处理,使结构更加清晰、灵活性更高。
重载的 visit 方法会对元素进行不同的操作,而通过注入不同的 Visitor 又可以替换掉访问者的具体实现,使得对元素的操作变得更灵活,可扩展性更高,同时也消除了类型转换、if-else 等“丑陋”的代码。
第三步、创建对象结构它内部管理了元素集合,并且可以迭代这些元素提供访问者访问。
将这些员工添加到一个业务报表类中,公司高层可以通过该报表类的 showReport 方法查看所有员工的业绩,具体代码如下:
/*** 员工业务报表类*/
public class BusinessReport {private List<Staff> mStaffs = new LinkedList();public BusinessReport() {mStaffs.add(new Manager("经理-A"));mStaffs.add(new Manager("经理-B"));mStaffs.add(new Engineer("工程师-A"));mStaffs.add(new Engineer("工程师-B"));mStaffs.add(new Engineer("工程师-C"));}/*** 为访问者展示报表* @param visitor 公司高层,如CEO、CTO*/public void showReport(Visitor visitor) {for (Staff staff : mStaffs) {staff.accept(visitor);}}
}
下面开始测试
public class Client {public static void main(String[] args) {// 构建报表BusinessReport report = new BusinessReport();System.out.println("=========== CEO看报表 ===========");report.showReport(new CEOVisitor());System.out.println("=========== CTO看报表 ===========");report.showReport(new CTOVisitor());}
}
=========== CEO看报表 ===========
经理: 经理-A, KPI: 1
经理: 经理-B, KPI: 7
工程师: 工程师-A, KPI: 4
工程师: 工程师-B, KPI: 7
工程师: 工程师-C, KPI: 9
=========== CTO看报表 ===========
经理: 经理-A, 产品数量: 3
经理: 经理-B, 产品数量: 4
工程师: 工程师-A, 代码行数: 90025
工程师: 工程师-B, 代码行数: 4854
工程师: 工程师-C, 代码行数: 35511
在上述示例中,Staff 扮演了 Element 角色,而 Engineer 和 Manager 都是 ConcreteElement;CEOVisitor 和 CTOVisitor 都是具体的 Visitor 对象;而 BusinessReport 就是 ObjectStructure;Client就是客户端代码。
访问者模式最大的优点就是增加访问者非常容易,我们从代码中可以看到,如果要增加一个访问者,只要新实现一个 Visitor 接口的类,从而达到数据对象与数据操作相分离的效果。如果不使用访问者模式,而又不想对不同的元素进行不同的操作,那么必定需要使用 if-else 和类型转换,这使得代码难以升级维护。
总结
我们要根据具体情况来评估是否适合使用访问者模式,例如,我们的对象结构是否足够稳定,是否需要经常定义新的操作,使用访问者模式是否能优化我们的代码,而不是使我们的代码变得更复杂。
-
访问者模式的优点。
- 各角色职责分离,符合单一职责原则
通过UML类图和上面的示例可以看出来,Visitor、ConcreteVisitor、Element 、ObjectStructure,职责单一,各司其责。 - 具有优秀的扩展性
如果需要增加新的访问者,增加实现类 ConcreteVisitor 就可以快速扩展。 - 使得数据结构和作用于结构上的操作解耦,使得操作集合可以独立变化
员工属性(数据结构)和CEO、CTO访问者(数据操作)的解耦。 - 灵活性
- 各角色职责分离,符合单一职责原则
-
访问者模式的缺点。
- 具体元素对访问者公布细节,违反了迪米特原则
CEO、CTO需要调用具体员工的方法。 - 具体元素变更时导致修改成本大
变更员工属性时,多个访问者都要修改。 - 违反了依赖倒置原则,为了达到“区别对待”而依赖了具体类,没有以来抽象
访问者 visit 方法中,依赖了具体员工的具体方法。
- 具体元素对访问者公布细节,违反了迪米特原则