1.简要说明什么是软件体系结构,软件体系结构模型,为什么要建立软件体系结构模型?
答:软件体系结构指一个软件系统在高层次上的结构化组织方式,包括系统的组成部分和各个部分之间的关系,以及它们与环境之间的交互,同时它描述了各个组件之间的联系和功能分配,为系统的设计、维护提供指导和支持。
软件体系结构模型是描述软件体系结构的抽象表达,通常以图形化的方式呈现,用于表达软件系统整体结构和各个部分之间的关系,包含组件、连接、约束等等。
使用软件体系结构模型可以使开发人员能够更好理解整个系统开发的结构和组成,使软件开发更加有序、高效,有益于软件的质量和可维护性。
2.简要说明什么是构件和软件重用?
答:构件(component):指的是一个系统中的模块或部件,具有独立的功能和接口,并且可以通过接口与其他构件进行交互和组合。它是软件系统的基本构成单位,它可以独立地进行开发、测试、部署和维护。
软件重用:将软件开发过程中完成并通过测试的模块、组件库等重复利用的过程。
3.4+1视图模型中各视图的作用。
答:逻辑视图:描述软件功能和系统架构的
开发视图:描述软件开发过程
过程视图:描述软件运行过程(交互、执行)
物理视图:描述软件的物理结构和部署方式(硬件环境)
场景视图:描述软件的使用场景和使用流程(用户需求)
4. UML模型图在软件体系结构建模中的作用。图的画法
答:用例图:描述用户的需求和功能
类图:用于描述软件的静态结构
活动图:描述软件系统结构的操作流程和业务流程
状态图:描述软件系统中的状态和状态转换
时序图:用于描述软件系统中的对象交互和信息传递的顺序
组件图:用于描述组件和依赖之间的关系
部署图:用于描述软件系统的物理部署结构
5.简单工厂模式和工厂方法模式的优缺点。
模式名称 优点 缺点
简单工厂模式 隐藏具体实现、降低客户端和实现类的耦合度 不易扩展、代码复杂度高
工厂方法模式 将创建对象交给子类进行,具有可扩展性、降低耦合度、代码可读性高 增加代码复杂度
6.WSDL文档开发客户端应用程序的流程。
答: WSDL (Web Server Description Language)
1.获取WDSL文件: web服务网址+“?WDSL”
2.生成客户端代码
3.编写客户端代码
4.部署客户端应用程序
5.测试
7.二层C/S、三层C/S、B/S,以及C/S与B/S混合架构风格示意图及其含义。
答:B/S(browser/server): 浏览器-服务端架构,由浏览器向服务器发送请求,服务器向浏览器页面进行响应。
C/S(client/server): 客户端-服务端,由客户端应用向服务器发送网络请求,有服务端向客户端应用响应。客户端通常负责处理用户界面和输入数据,而服务器则负责处理应用程序逻辑和数据存储。
三层C/S,它将应用程序分成三个层次:表示层(Presentation Layer)、应用层(Application Layer)和数据层(Data Layer)。表示层负责处理用户界面,应用层负责处理应用程序逻辑,数据层负责处理数据存储和检索。
B/S、C/S混合架构:指将B/S架构和C/S架构进行结合,通过服务器端的中间件来协调前端浏览器和后端应用程序之间的交互。在这种架构中,前端用户界面仍然是基于浏览器的Web应用程序,但是通过中间件与后端服务器进行交互,后端服务器可以提供更多的应用逻辑和数据处理功能。
8.设计模式以及对应的编程
// 产品接口
public interface Product {
void use();}
// 具体产品1
public class ConcreteProduct1 implements Product {
public void use() {
System.out.println(“I am ConcreteProduct1.”); }}
// 具体产品2
public class ConcreteProduct2 implements Product {
public void use() {
System.out.println(“I am ConcreteProduct2.”); }}
// 工厂类
public class Factory {
public static Product createProduct(String type) {
if (“Product1”.equals(type)) {
return new ConcreteProduct1();
} else if (“Product2”.equals(type)) {
return new ConcreteProduct2();
} else {
return null; } }}
// 客户端
public class Client {
public static void main(String[] args) {
Product product1 = Factory.createProduct(“Product1”);
product1.use();
Product product2 = Factory.createProduct(“Product2”);
product2.use();}]
9.某客户要求开发一个无人自动售货机系统,主要需求调研记录如下:送货员在每周固定时间查看售货机中的商品数量和钱币数量情况,并根据计划适当添加商品、钱币或取走适当的钱币。同时,送货员也可以根据需要增加商品的种类,或修改商品的价格。售货时,顾客把钱币投入机器的投币口中,机器检查钱币的真伪,如果发现假币机器拒收,并将其从退币口退出。当机器接收了有效的钱币之后,将之送入钱币储藏器。顾客支付的货币根据钱币的面值进行累加。自动售货机装有货物分配器,每个分配器中包含0个或多个价格相同的货物。顾客通过选择货物分配器来选择货物。如果有货,且顾客支付的货币值不小于该货物的价格,货物将被分配到货物传送孔送给顾客,并将找零返回到退币口。如果无货,则和顾客支付的货币值相等的钱币将被送到退币口。如果顾客支付的货币值小于所选货物的价格,机器将等待顾客投进更多的货币。如果顾客决定不买所选择的货物,他投放进的钱币将从退币口中退出。
请根据以上描述,进行分析设计,完成UML多视图体系架构建模任务:
为了完成这个无人自动售货机系统的设计,需要进行多视图体系架构建模任务。下面将分别从逻辑视图、进程视图、物理视图
1.逻辑视图 逻辑视图描述系统的静态结构和行为。在这个自动售货机系统中,存在以下类:
VendingMachine:自动售货机类,负责售货、找零等操作。
Coin:钱币类,包括面值、数量、真伪等属性。
Product:商品类,包括名称、价格等属性。
Dispenser:分配器类,包括存储的商品、库存等属性。
Refund:退款类,记录退款的钱币和数量。
类之间的关系如下:
VendingMachine和Coin之间是一对多的关系,即一个自动售货机可以接收多种面值的钱币。
VendingMachine和Product之间是多对多的关系,即一个自动售货机可以有多种商品,一个商品可以被多个自动售货机售卖。
VendingMachine和Dispenser之间是一对多的关系,即一个自动售货机可以有多个分配器,一个分配器只属于一个自动售货机。
VendingMachine和Refund之间是一对多的关系,即一个自动售货机可以有多个退款记录,一个退款记录只属于一个自动售货机。
进程视图 进程视图描述系统的动态行为。在这个自动售货机系统中,存在以下进程:
VendingMachineProcess:自动售货机进程,负责处理售货、找零等业务逻辑。
RefundProcess:退款进程,负责退款操作。
自动售货机进程接收来自客户端的请求,包括选择商品、投入钱币、查询库存等。如果客户投入的钱币足够支付选择的商品,自动售货机进程将发起退款进程,完成找零和出货的操作。如果客户选择的商品无货或投入的钱币不足,自动售货机进程将等待客户继续投入钱币或重新选择商品。
1.物理视图 物理视图描述系统的物理组成和部署。在这个自动售货机系统中,存在以下物理组件:
Client
VendingMachineDevice:自动售货机设备,包括货物分配器、钱币投入口、退币口、货物传送孔等组件。
VendingMachineServer:自动售货机服务器,负责接收客户端请求并调用自动售货机进程处理请求。
一.软件详细设计
自选一个项目,完成一个模块的详细设计,具体包括:
1.描述清楚项目名称,模块功能
2.UML类图
3.正向工程源码
public class Ability {
String abilityName=null;
public Ability(){
}
public String getAbilitylName() {
return abilityName;
}
public void setAbilityName(String abilityName) {
this.abilityName = abilityName;
}
}
public class Learn extends Ability{
public Learn(String abilityName) {
super();
this.abilityName = abilityName;
}
public void JavaClass(){
System.out.println(this.abilityName+"我擅长Java语言!");
}
public void math(){
System.out.println(this.abilityName+"我擅长高等数学!");
}
}
public class Sports extends Ability{
public Sports(String abilityName) {
super();
this.abilityName = abilityName;
}
public void run(){
System.out.println(this.abilityName+"我擅长长跑!");
}
public void climb(){
System.out.println(this.abilityName+"我擅长攀岩!");
}
}public class Main {
public static void main(String[] args) {
Ability abilityLearn = new Learn("学习能力");
Learn learn = (Learn) abilityLearn;
learn.JavaClass();
learn.math();
Ability abilitySports = new Sports("运动能力");
Sports sports = (Sports) abilitySports;
sports.run();
sports.climb();
}
}
二.软件设计模式:单例模式类图及两种实现方式源码(自定义类)
双重检查模式DCL:
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){
}
public static Singleton getInstance() {
if (instance== null) {
synchronized (Singleton.class) {
if (instance== null) {
instance= new Singleton(); } } }
return singleton; } }
静态内部类实现:
public class Singleton {
private Singleton() { }
public static Singleton getInstance() {
return SingletonHolder.instance; }
/**
* 静态内部类
*/
private static class SingletonHolder {
private static Singleton instance = new Singleton();
}
}
三.软件设计模式:简单工厂模式类图及源码
package Operation;
public abstract class Operation {
double numberA=0;
double numberB=0;
public double getNumberA() {
return numberA; }
public void setNumberA(double numberA) {
this.numberA = numberA; }
public double getNumberB() {
return numberB; }
public void setNumberB(double numberB) {
this.numberB = numberB; }
public abstract double operate(); }
加类:
Java代码
package Operation;
public class Add extends Operation {
@Override
public double operate() {
return numberA+numberB;
}
}
减类:
Java代码
package Operation;
public class Sub extends Operation {
@Override
public double operate() {
return numberA-numberB; } }
乘类:
Java代码
package Operation;
public class Mul extends Operation {
@Override
public double operate() {
return numberAnumberB; } }
除类:
Java代码
package Operation;
import java.io.IOError;
public class Div extends Operation {
@Override
public double operate() {
try {
return numberA/numberB;
} catch (IOError e) {
System.out.println(“除数不能为空!”);
return 0; } } }
工厂类:
Java代码
import Operation.Add;
import Operation.Div;
import Operation.Mul;
import Operation.Operation;
import Operation.Sub;
public class OperationFactory {
public static Operation createOperation(char operate){
Operation operation=null;
switch (operate) {
case ‘+’:
operation=new Add();
break;
case ‘-’:
operation=new Sub();
break;
case '‘:
operation=new Mul();
break;
case ‘/’:
operation=new Div();
break; }
return operation; } }
客户端:
Java代码
import Operation.Operation;
public class Client {
public static void main(String[] args) {
Operation operation = OperationFactory.createOperation(’*');
operation.setNumberA(12);
operation.setNumberB(6);
System.out.println(operation.operate());
}
}
四.设计软件模式:模板方法模式类图及源码
package com.amosli.dp.behavior.template;
public abstract class AbstractClass {
public void templateMethod(){
primitiveMethod1();
primitiveMethod2();}
public abstract void primitiveMethod1();
public abstract void primitiveMethod2();}
package com.amosli.dp.behavior.template;
public class ConcreteClassA extends AbstractClass{
@Override
public void primitiveMethod1() {
System.out.println(“ConcreteClassA primitive method 1…”);}
@Override
public void primitiveMethod2() {
System.out.println(“ConcreteClassA primitive method 2…”);}}
package com.amosli.dp.behavior.template;
public class ConcreteClassB extends AbstractClass{
@Override
public void primitiveMethod1() {
System.out.println(“ConcreteClassB primitive method 1…”);}
@Override
public void primitiveMethod2() {
System.out.println(“ConcreteClassB primitive method 2…”);}}
package com.amosli.dp.behavior.template;
public class Client {
public static void main(String[] args) {
AbstractClass abstractClass = new ConcreteClassA();
abstractClass.templateMethod();
abstractClass = new ConcreteClassB();
abstractClass.templateMethod();}}
五.软件架构:请阐述分布式服务框架Dubbo,包括:
1)Dubbo是什么
2)Dubbo有什么用
3)为什么使用Dubbo
4)什么时候使用Dubbo
答:1、Dubbo是什么?
Dubbo是阿里巴巴开源的基于 Java 的高性能 RPC 分布式服务框架,现已成为 Apache 基金会孵化项目,是一个分布式服务框架,致力于提供高性能和透明化的RPC远程服务调用方案,以及SOA服务治理方案。
2、为什么要用Dubbo?
因为是阿里开源项目,国内很多互联网公司都在用,已经经过很多线上考验。内部使用了 Netty、Zookeeper,保证了高性能高可用性。
使用 Dubbo 可以将核心业务抽取出来,作为独立的服务,逐渐形成稳定的服务中心,可用于提高业务复用灵活扩展,使前端应用能更快速的响应多变的市场需求。
当网站规模达到了一定的量级的时候,普通的MVC框架已经不能满足我们的需求,于是分布式的服务框架和流动式的架构就凸显出来了。
3.有什么用
1.透明化的远程方法调用,就像调用本地方法一样调用远程方法,只需简单配置,没有任何API侵入。
2.软负载均衡及容错机制,可在内网替代F5等硬件负载均衡器,降低成本,减少单点。
3. 服务自动注册与发现,不再需要写死服务提供方地址,注册中心基于接口名查询服务提供者的IP地址,并且能够平滑添加或删除服务提供者。
Dubbo的存在简单来说就是要减小service层的压力。
4.什么时候使用
当网站变大后,不可避免的需要拆分应用进行服务化,以提高开发效率,调优性能,节省关键竞争资源等。
当服务越来越多时,服务的URL地址信息就会爆炸式增长,配置管理变得非常困难,F5硬件负载均衡器的单点压力也越来越大。
当进一步发展,服务间依赖关系变得错踪复杂,甚至分不清哪个应用要在哪个应用之前启动,架构师都不能完整的描述应用的架构关系。
六.软件架构:请阐述Redis,包括:
1)Redis是什么
2)Redis有什么用
3)为什么使用Redis
4)什么场景下使用Redis
答:1 redis是什么?
通常而言目前的数据库分类有几种,包括 SQL/NSQL,,关系数据库,键值数据库等等 等,分类的标准也不以,Redis本质上也是一种键值数据库的,但它在保持键值数据库简单快捷特点的同时,又吸收了部分关系数据库的优点。从而使它的位置处于关系数据库和键值数 据库之间。Redis不仅能保存Strings类型的数据,还能保存Lists类型(有序)和Sets类型(无序)的数据,而且还能完成排序(SORT) 等高级功能,在实现INCR,SETNX等功能的时候,保证了其操作的原子性,除此以外,还支持主从复制等功能。
2 Redis有什么用?
通常局限点来说,Redis也以消息队列的形式存在,作为内嵌的List存在,满足实时的高并发需求。而通常在一个电商类型的数据处理过程之中,有关商品,热销,推荐排序的队列,通常存放在Redis之中,期间也包扩Storm对于Redis列表的读取和更新。
3、为什么使用
解决应用服务器的cpu和内存压力
减少io的读操作,减轻io的压力
关系型数据库的扩展性不强,难以改变表结构
4、什么时候用:
数据高并发的读写
海量数据的读写
对扩展性要求高的数据
七.软件架构:请阐述RabbitMQ,包括:
1)RabbitMQ是什么
2)RabbitMQ有什么用
3)为什么使用RabbitMQ
4)什么场景下使用RabbitMQ
答:1.什么是rabbitmq
RabbitMQ是支持持久化消息队列的消息中间件。应用在上下游的层次级业务逻辑中,上级业务逻辑相当于生产者发布消息,下级业务逻辑相当于消费者接受到消息并且消费消息。
采用AMQP高级消息队列协议的一种消息队列技术,最大的特点就是消费并不需要确保提供方存在,实现了服务之间的高度解耦
2.为什么要使用rabbitmq
1.在分布式系统下具备异步,削峰,负载均衡等一系列高级功能;
2.拥有持久化的机制,进程消息,队列中的信息也可以保存下来。
3.实现消费者和生产者之间的解耦。
4.对于高并发场景下,利用消息队列可以使得同步访问变为串行访问达到一定量的限流,利于数据库的操作。
5.可以使用消息队列达到异步下单的效果,排队中,后台进行逻辑下单。
3、有什么用:
1.解耦,系统A在代码中直接调用系统B和系统C的代码,如果将来D系统接入,系统A还需要修改代码,过于麻烦!
2.异步,将消息写入消息队列,非必要的业务逻辑以异步的方式运行,加快响应速度
3.削峰,并发量大的时候,所有的请求直接怼到数据库,造成数据库连接异常
4.什么时候使用rabbitmq的场景
1.服务间异步通信
2.顺序消费
3.定时任务
4.请求削峰
八、SpringAOP体现了哪些软件设计原则,有什么好处
开闭原则、里式替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特原则
Aop优点减少重复代码,提高开发效率,不修改源码对已有方法进行增强。
九、Spring中的IOC体现了哪些软件设计原则?有什么好处
开闭原则、里式替换原则、依赖倒置原则、单一职责原则、接口隔离原则、迪米特原则、合成复用原则、
优点:当下层需要改变时,只要接口及接口功能不变,则上层不需要做任何改变,甚至可以在不改动上层代码是将下层整个替换掉
简答题汇总
1、什么是设计模式?设计模式目标是什么?
设计模式是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。使用设计模式是为了可重用代码、让代码更容易被他人理解,保证代码可靠性。
2、设计模式中一般都遵循的原则有什么?
开闭原则、根据场景进行设计原则、优先组合原则、包容变化原则
3、“Gang of Four”针对“创建优秀面向对象设计”建议了哪些策略?
针对接口编程、优先使用对象组合而不是类继承,找到并封装变化点。
4、面向对象系统中功能复用的两种最常用技术是什么?
类继承和对象组合,类继承允许你根据其他类的实现来定义一个类的实现。父类的内部细节对子类可见。类继承是在编译时刻静态定义的,且可直接使用,类继承可以较方便地改变被复用的实现。对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组装或组合对象来获得。对象组合要求被组合的对象具有良好定义的接口。
5、只根据抽象类中定义的接口来操纵对象有什么好处?
1) 客户无须知道他们使用对象的特定类型,只须对象有客户所期望的接口。
2) 客户无须知道他们使用的对象是用什么类来实现的,他们只须知道定义接口的抽象类。
6、在MVC模型中M、V、C分别指什么?简述它们之间的关系?
M:模型(Model),V:视图(View),C:控制Controller)。
MVC模式的目的就是实现Web系统的职能分工。
Model层实现系统中的业务逻辑,通常可以用JavaBean或EJB来实现。
View层用于与用户的交互,通常用JSP来实现。
Controller层是Model与View之间沟通的桥梁,它可以分派用户的请求并选择恰当的视图以用于显示,同时它也可以解释用户的输入并将它们映射为模型层可执行的操作。
7、什么是开闭原则?
软件实体应当对扩展开放,对修改关闭,软件系统中包含的各种组件,例如模块(Modules)、类(Classes)以及功能(Functions)等,应该在不修改现有代码的基础上,引入新功能。开闭原则中“开”,是指对于组件功能的扩展是开放的,是允许对其进行功能扩展的;开闭原则中“闭”,是指对于原有代码的修改是封闭的,即不应该修改原有的代码。
8、设计数据库的系统日志,要考虑使用哪些设计模式?
命令模式,备忘录模式,外观模式
9、使用工厂模式的主要原因是什么?
工厂模式定义:提供创建对象的接口。因为工厂模式就相当于创建实例对象的new,我们经常要根据类Class生成实例对象,如A a=new A() 工厂模式也是用来创建实例对象的,所以以后new时就要多个心眼,是否可以考虑使用工厂模式,虽然这样做,可能多做一些工作,但会给你系统带来更大的可扩展性和尽量少的修改量。
10、在面向对象设计中,《编译原理》的有限状态机可以什么样解决方案完成?猫大叫一声,所有的老鼠都开始逃跑,主人被惊醒问:(1)设计可能用到什么设计模式?(2)画出其类图。
观察者模式分析:要有联动性,老鼠和主人的行为是被动的;考虑可扩展性,猫的叫声可能引起其他联动效应。
11、单例模式的两种实现方法,并说明优缺点?
懒汉式,在类被加载时,唯一的实例已经被创建。这个模式在java中很容易实现,在其他语言中很难。
饿汉式,在类加载的时候不创建单例实体。只有在第一次请求实例的时候创建,并且只在第一次创建后不再创佳该类的实例。
12、什么是对象粒度?
所谓的对象粒度就是对象从抽象到具体的描述的程度。同样一个系统,同样的需求。两个设计师给出两种设计。两个设计代码行数差不多,但是类的数目不同。例如有一个对象,我可以用10行代码去构造它,我也可以用20行代码,后者比前者更为精确。
13、MVC模式是个复合模式,请写出你两种你所知道的MVC中使用的模式。
观察者模式:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
策略模式:定义了算法族,分别封装起来,让他们之间可以相互替换,此模式让算法的变化独立于使用算法的客户。
14、举例说明,适配器模式和装配器在Java IO中的应用。
装饰者模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器可以对另一些流处理器起到装饰作用,形成新的,具有改善了的功能的流处理器。装饰者模式是Java I/O库的整体设计模式。这样的一个原则是符合装饰者模式的。
适配器模式:在由InputStream,OutputStream,Reader和Writer代表的等级结构内部,有一些流处理器是对其它类型的流源的适配。这就是适配器模式的应用,适配器模式应用到了原始流处理器的设计上面,构成了I/O库所有流处理器的起点。
15、在面向对象程序设计中,常常需要避免过多case语句或者if语句,请给出一种设计模式避免过多的条件分支语句,同时指出这种设计模式如何帮助避免过多的Case语句?
访问者模式。例如 switch(pt){ case A: break; case B: break; … }
把每个条件作成一个类,比如 A条件 class A { public void accept() {//处理逻辑 } }
然后把每个条件的处理方法都用一个类来管理. public class CommonVisitor{ public void visit(A a){a.accept();}//其他条件的访问方法 public void visit(B b){ b.accept();}}
main里面就这样调用就行。public static void main(Stirng args[]){CommonVisitor visitor = new CommonVisitor();//如果是想用A条件,则visitor.visit(new A());} 这样写的好处,以后先加条件的话我只需要定义新的条件类就行,还有就是在CommonVisitor添加新条件的访问方法就行,这样就很好作到一个条件管理一个逻辑。
应用题汇总
1、公司架构:经理、工程师、技师和后勤人员都是公司的雇员,经理管理工程师、技师和后勤人员。高层经理领导较低级别的经理。典型层次图如下:可以使用哪种设计模式实现公司的层级关系?并说明为什么? 组合模式,第一,其公司关系架构为树形结构;第二,其表示了部分-整体关系(自己扩展)
2、认真分析以下类图
要求:①说明选择了什么设计模式?②写出其程序代码。
解:①本题使用了迭代器模式 ②其参考程序代码如下所示:
interface Aggregate{
Iterator createIterator();}
interface Iterator{
void first();
void next();
boolean hasNext();
Object currentItem();}
class ConcreteAggregate implements Aggregate{
private Object[] obj={“筷”,“杯”,"锅”,“碗”,“瓢”,“盆”};
public Iterator createIterator(){
return new ConcreteIterator();}
private class ConcreteIterator implements Iterator{
private int currentIndex=0;
public void first(){
currentIndex=0;}
public void next(){
if(currentIndex < obj.length){
currentIndex++;}}
public boolean hasNext(){
return currentIndex < obj.length;}
public Object currentItem(){
return obj[currentIndex];}}}
class Client{
public static void process(Aggregate a){
Iterator i = a.createIterator();
while(i.hasNext()){
System.out.println(i.currentItem().toString());
i.next();}}
public static void main(String a[]){
Aggregate a = new ConcreteAggregate();
process(a);}}
3、某旅游公司(如:广之旅)欲利用假期为韶关学院学生开展夏令营活动,帮助大学生同国外大学生交流,根据如下描述选择合适的设计模式进行设计。1)该公司能帮助学生同国外多个大学生联系,如:哈佛大学、墨尔本大学;2)公司为每个国外大学分配一名翻译,如:中英翻译、中澳翻译。要求:(1)正确选择设计模式(2)画出其类图(3)正确解释该类图中的成员角色
解:
对于描述1可以选择使用中介者模式,对于描述2可以选择使用适配器模式,参考类图如下所示
在类图中,各类的角色如下:
1)旅游公司:抽象中介者;
2)广之旅:具体中介者;
3)大学生:抽象同事类;
4)韶关学院学生:是具体同事类,也是目标抽象类;
5)哈佛大学生、墨尔本大学生:是具体同事类,也是适配者类;
6)翻译1、翻译2:适配器类。