设计模式 (Design pattern)是一套被反复使用的、经过分类编目的面向对象程序设计经验总结。它是面向对象程序设计中典型问题的解决方案。
GoF模式是四位著名面向对象设计专家 (Elich Gamma、Richard Helm、Ralph Johnson、 John Vlissides) 所提出的23种面向对象程序设计模式。这四个人常被称为Gang of Four,简称GoF。
序号 | 模式类型 | 说明 |
---|---|---|
1 | 创造模式 | 与对象创建有关,提供一种创建对象而隐藏创建逻辑,给出灵活创建对象的解决方案。典型模式有5种。 |
2 | 结构模式 | 处理类或对象的组合,给出利用继承、接口组合对象以获得新功能的解决方案。典型模式有7种。 |
3 | 行为模式 | 用于描述对象之间协作完成特定功能及其职责分配,给出对象之间通信的解决方案。典型模式有11种。 |
创建型模式的关注点是“怎样创建对象?”它的主要特点是“将对象的创建与使用分离”,从而降低对象之间的耦合度。
一、创建型模式类型
单例模式是指一个类只能有一个实例,且该类能自行创建这个实例的一种程序设计模式。
虽然软件系统可以创建多个进程任务并发运行,但系统在同一时段只允许一个进程任务运行处理。如下一些计算机软件程序需要采用单一进程处理。
如何让系统只允许唯一的实例进行服务资源访问,从而解决多实例模式带来的系统开销问题。
解决问题思想:
饿汉式单例类:在单例类被初始化加载时,就实例化一个对象交给自己的引用。
// 饿汉式单例类
public class Singleton {
private static Singleton singletonVar = new Singleton();//在定义变量时就创建对象
private Singleton() {
} //私有的构造方法
public static Singleton getInstance() { //静态公有方法返回创建的对象
return singletonVar;
}
}
懒汉式单例类:在访问实例对象时才实例化对象。
public class Singleton {
private static Singleton singletonVar; //私有的静态对象变量
private Singleton() {
} //私有的构造方法
public static synchronized Singleton getInstance() { //访问实例对象时创建单例类实例
if (singletonVar == null) {
singletonVar = new Singleton();
}
return singletonVar;
}
}
synchronized关键字的作用是实现线程同步,保证在同一时刻只有一个线程能够访问某个资源。在懒汉式单例类中,getInstance()方法是获取单例对象的唯一入口,因此使用synchronized关键字可以保证在多线程环境下,只有一个线程能够创建单例对象,从而保证单例对象的唯一性。如果不使用synchronized关键字,在多线程环境下,可能会有多个线程同时执行getInstance()方法,从而导致多个单例对象被创建。这将会破坏单例模式的设计意图。
SingletonLazy类编程代码:
public class SingletonLazy {
public static void main(String[] args) {
President zt1 = President.getInstance();
zt1.getName(); // 输出总统的名字
President zt2 = President.getInstance();
zt2.getName(); // 输出总统的名字
if (zt1 == zt2) {
System.out.println("他们是同一人!");
} else {
System.out.println("他们不是同一人!");
}
}
}
President类编程代码:
class President {
private static volatile President instance = null; //保证 instance 在所有线程中同步
//private避免类在外部被实例化
private President() {
System.out.println("产生一个总统!");
}
public static synchronized President getInstance() {
//在getInstance方法上加静态锁,避免并发线程访问产生多个实例
if (instance == null) {
instance = new President();
} else {
System.out.println("已经有一个总统,不能产生新总统!");
}
return instance;
}
public void getName() {
System.out.println("我是美国总统:拜登。");
}
}
完整代码:
public class SingletonLazy {
public static void main(String[] args) {
President zt1 = President.getInstance();
zt1.getName(); // 输出总统的名字
President zt2 = President.getInstance();
zt2.getName(); // 输出总统的名字
if (zt1 == zt2) {
System.out.println("他们是同一人!");
} else {
System.out.println("他们不是同一人!");
}
}
}
class President {
private static volatile President instance = null; //保证 instance 在所有线程中同步
//private避免类在外部被实例化
private President() {
System.out.println("产生一个总统!");
}
public static synchronized President getInstance() {
//在getInstance方法上加静态锁,避免并发线程访问产生多个实例
if (instance == null) {
instance = new President();
} else {
System.out.println("已经有一个总统,不能产生新总统!");
}
return instance;
}
public void getName() {
System.out.println("我是美国总统:拜登。");
}
}
运行结果:
优点:
缺点:
针对如下民政服务系统的婚姻登记功能设计类图,如何采用饿汉式单例模式实现Java程序编写,并在主程序中输出消息反馈。
class MarriageRegister {
// 私有静态实例,在类加载时创建
private static final MarriageRegister instance = new MarriageRegister();
// 私有构造方法,防止外部通过new创建多个实例
private MarriageRegister() {
// 初始化操作
}
// 公有静态方法,返回唯一实例
public static MarriageRegister getInstance() {
return instance;
}
// 公有方法,输出消息
public void showMessage() {
System.out.println("Marriage registration is successful.");
}
}
public class Client {
public static void main(String[] args) {
// 获取MarriageRegister的单例实例
MarriageRegister register = MarriageRegister.getInstance();
// 输出消息
register.showMessage();
}
}
运行结果:
结构型模式描述如何将类或对象组成更大的结构实现特定功能特性。它分为类结构型模式和对象结构型模式。前者采用继承机制来组织接口和类,后者采用组合或聚合来组织对象。
适配器模式实现不同类接口之间的转换,使接口不兼容的那些类也能一起工作。
当利用现有的类库实现系统的新功能开发时,发现当前系统的接口与现有类库规范不兼容。如果重新开发这些类成本又很高,这时可以使用适配器模式来解决现有类的复用问题。
系统需要使用现有的类,但该类的接口不符合系统的访问需要。
如何通过接口转换,使一个类可以访问另一个类。
package adapter;
//目标接口
interface Target {
public void request();
}
//被适配者类
class Adaptee {
public void specificRequest() {
System.out.println("适配者中的业务代码被调用!");
}
}
// 适配器类
class ClassAdapter extends Adaptee implements Target {
public void request() {
specificRequest();
}
}
// 客户端测试代码
public class ClassAdapterTest {
public static void main(String[] args) {
System.out.println("类适配器模式测试:");
Target target = new ClassAdapter();
target.request();
}
}
运行输出结果:
为了实现AudioPlayer播放其他格式的音频文件。需要创建一个实现 MediaPlayer接口的适配器类MediaAdapter。该适配器类使用AdvancedMediaPlayer类的对象来播放所需的媒体文件格式。
Audioplayer 使用适配器类MediaAdapter 传递所需的音频类型,它不需要知道能播放所需格式音频的实际类。
AdapterPatternDemo 类使用AudioPlayer 类和适配器类MediaAdapter 来播放各种格式文件。
MediaPlayer接口:
package AdapterPattern;
//媒体播放器接口
public interface MediaPlayer {
public void play(String audioType, String fileName);
}
AdvancedMediaPlayer接口:
package AdapterPattern;
//高级媒体播放器接口
public interface AdvancedMediaPlayer {
public void playVlc(String fileName);
public void playMp4(String fileName);
}
VlcPlayer类:
package AdapterPattern;
//创建实现了 AdvancedMediaPlayer 接口的实体类
public class VlcPlayer implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
System.out.println("播放 vlc file. Name: " + fileName);
}
@Override
public void playMp4(String fileName) {
//什么也不做
}
}
Mp4Player类:
package AdapterPattern;
//创建实现了 AdvancedMediaPlayer 接口的实体类
public class Mp4Player implements AdvancedMediaPlayer {
@Override
public void playVlc(String fileName) {
//什么也不做
}
@Override
public void playMp4(String fileName) {
System.out.println("播放 mp4 file. Name: " + fileName);
}
}
MediaAdapter类:
package AdapterPattern;
public class MediaAdapter implements MediaPlayer {
AdvancedMediaPlayer advancedMusicPlayer;
public MediaAdapter(String audioType) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer = new VlcPlayer();
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer = new Mp4Player();
}
}
@Override
public void play(String audioType, String fileName) {
if (audioType.equalsIgnoreCase("vlc")) {
advancedMusicPlayer.playVlc(fileName);
} else if (audioType.equalsIgnoreCase("mp4")) {
advancedMusicPlayer.playMp4(fileName);
}
}
}
AudioPlayer类:
package AdapterPattern;
public class AudioPlayer implements MediaPlayer {
MediaAdapter mediaAdapter;
@Override
public void play(String audioType, String fileName) {
// 播放 mp3 音乐文件的内置支持
if (audioType.equalsIgnoreCase("mp3")) {
System.out.println("Playing mp3 file. Name: " + fileName);
}
// mediaAdapter 提供了播放其他文件格式的支持
else if (audioType.equalsIgnoreCase("vlc")
|| audioType.equalsIgnoreCase("mp4")) {
mediaAdapter = new MediaAdapter(audioType);
mediaAdapter.play(audioType, fileName);
} else {
System.out.println("Invalid media. " +
audioType + " format not supported");
}
}
}
AdapterPatternDemo类:
package AdapterPattern;
//使用AudioPlayer来播放不同类型的音频格式
public class AdapterPatternDemo {
public static void main(String[] args) {
AudioPlayer audioPlayer = new AudioPlayer();
audioPlayer.play("mp3", "beyond the horizon.mp3");
audioPlayer.play("mp4", "alone.mp4");
audioPlayer.play("vlc", "far far away.vlc");
audioPlayer.play("avi", "mind me.avi");
}
}
运行结果:
补:equalsIgnoreCase 是 Java 中的一个方法,用于比较两个字符串是否相等,而忽略它们的大小写。这个方法是 String 类的成员,所以可以对任何字符串对象调用它。
优点:
缺点:
分析下面设计类图如何解决新能源汽车的发动机接口?给出Java程序实现该设计功能。
// Motor接口
interface Motor {
void drive();
}
// 电动电机类
class ElectricMotor {
public void electricDrive() {
System.out.println("Electric Motor drive.");
}
}
// 光电电机类
class OpticalMotor {
public void opticalDrive() {
System.out.println("Optical Motor drive.");
}
}
// 电动电机适配器
class ElectricAdapter implements Motor {
private ElectricMotor emotor;
public ElectricAdapter() {
emotor = new ElectricMotor();
}
public void drive() {
emotor.electricDrive();
}
}
// 光电电机适配器
class OpticalAdapter implements Motor {
private OpticalMotor omotor;
public OpticalAdapter() {
omotor = new OpticalMotor();
}
public void drive() {
omotor.opticalDrive();
}
}
// 读取XML配置文件
class ReadXML {
// 这里提供一个示例方法,用于模拟从XML配置中获取电机对象
public static Object getObject() {
// 这里可以根据实际情况读取XML配置,实例化不同的Motor
// 以下代码仅作为示例
return new ElectricAdapter(); // 或者 return new OpticalAdapter();
}
}
public class MotorAdapterTest {
public static void main(String[] args) {
// 假设ReadXML.getObject()方法返回一个Motor类型的对象
Motor motor = (Motor) ReadXML.getObject();
motor.drive();
}
}
运行结果:
桥接模式是一种用于把抽象类与实现类解耦,使得二者都可以实现独立变化的设计模式。它通过在抽象类和实现类之间加入桥接接口,来实现二者的解耦。
在一些应用中,某些类具有多个维度的变化,如既可按形状扩展,又可按颜色扩展。如果类采用继承方式实现m种形状和n种颜色进行扩展建模,其子类就有 m×n 种,其扩展较困难。当采用桥接模式可以将抽象类与实现类解耦,使得二者可以独立变化,从而容易实现功能类扩展。
package bridge;
public class BridgeTest {
public static void main(String[] args) {
Implementor imple = new ConcreteImplementorA();
Abstraction abs = new RefinedAbstraction(imple);
abs.Operation();
}
}
//实现化接口
interface Implementor {
public void OperationImpl();
}
//具体实现化类
class ConcreteImplementorA implements Implementor {
public void OperationImpl() {
System.out.println("具体实现化(Concrete Implementor)角色被访问");
}
}
//抽象化角色
abstract class Abstraction {
protected Implementor imple;
protected Abstraction(Implementor imple) {
this.imple = imple;
}
public abstract void Operation();
}
//扩充抽象化角色
class RefinedAbstraction extends Abstraction {
protected RefinedAbstraction(Implementor imple) {
super(imple);
}
public void Operation() {
System.out.println("扩充抽象化(Refined Abstraction)角色被访问");
imple.OperationImpl();
}
}
运行结果:
package BridgePattern;
//画图API接口
interface DrawAPI {
public void drawCircle(int radius, int x, int y);
}
//红色圆圈的具体实现
class RedCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: red, radius: " + radius + ", x: " + x + ", y: " + y + "]");
}
}
//绿色圆圈的具体实现
class GreenCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: green, radius: " + radius + ", x: " + x + ", y: " + y + "]");
}
}
//抽象的形状类
abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI) {
this.drawAPI = drawAPI;
}
public abstract void draw();
}
//圆形类的实现
class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius, x, y);
}
}
//桥接模式的演示类
public class BridgePatternDemo {
public static void main(String[] args) {
Shape redCircle = new Circle(100, 100, 10, new RedCircle());
Shape greenCircle = new Circle(100, 100, 10, new GreenCircle());
redCircle.draw();
greenCircle.draw();
}
}
运行结果:
优点:
缺点:
分析如下女士皮包选购功能类图设计如何应用桥接模式?如何编写Java程序实现该功能。
// Color接口及其具体实现
interface Color {
String getColor();
}
class Yellow implements Color {
public String getColor() {
return "yellow";
}
}
class Red implements Color {
public String getColor() {
return "red";
}
}
// Bag抽象类及其具体实现
abstract class Bag {
protected Color color;
public void setColor(Color color) {
this.color = color;
}
public abstract String getName();
}
class HandBag extends Bag {
public String getName() {
return "HandBag";
}
}
class Wallet extends Bag {
public String getName() {
return "Wallet";
}
}
// BagManage类来展示如何使用桥接模式
public class BagManage {
public static void main(String[] args) {
// 创建具体实现化角色
Color yellow = new Yellow();
Color red = new Red();
// 创建扩充抽象化角色,并桥接具体实现化角色
Bag handBag = new HandBag();
handBag.setColor(yellow); // 设置黄色
Bag wallet = new Wallet();
wallet.setColor(red); // 设置红色
// 操作
System.out.println("The " + handBag.getName() + " is " + handBag.color.getColor());
System.out.println("The " + wallet.getName() + " is " + wallet.color.getColor());
}
}
运行结果:
行为型模式用于解决程序在运行时存在的复杂流程控制,如多个对象之间相互协作完成功能任务,以及如何分配职责。
责任链模式是一种通过对象链进行请求处理的设计模式。
为了避免请求发送者与多个处理者耦合在一起,仅需将请求发生给责任链首个对象,后续在该链的对象中传递处理,直到有某对象处理它为止。
package chainOfResponsibility;
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNext(handler2);
handler1.handleRequest("two");
}
}
abstract class Handler {
private Handler next;
public void setNext(Handler next) {
this.next = next;
}
public Handler getNext() {
return next;
}
public abstract void handleRequest(String request);
}
class ConcreteHandler1 extends Handler {
public void handleRequest(String request) {
if (request.equals("one")) {
System.out.println("具体处理者1负责处理请求!");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有人处理该请求!");
}
}
}
}
class ConcreteHandler2 extends Handler {
public void handleRequest(String request) {
if (request.equals("two")) {
System.out.println("具体处理者2负责处理请求!");
} else {
if (getNext() != null) {
getNext().handleRequest(request);
} else {
System.out.println("没有人处理该请求!");
}
}
}
}
运行结果:
package ChainResponsibilityPattern;
// 创建抽象的记录器类
abstract class AbstractLogger {
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
// 责任链中的下一个元素
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger) {
this.nextLogger = nextLogger;
}
public void logMessage(int level, String message) {
if (this.level <= level) {
write(message);
}
if (nextLogger != null) {
nextLogger.logMessage(level, message);
}
}
abstract protected void write(String message);
}
// 创建扩展了该记录器类的实体类
class ConsoleLogger extends AbstractLogger {
public ConsoleLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Standard Console::Logger: " + message);
}
}
class ErrorLogger extends AbstractLogger {
public ErrorLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("Error Console::Logger: " + message);
}
}
class FileLogger extends AbstractLogger {
public FileLogger(int level) {
this.level = level;
}
@Override
protected void write(String message) {
System.out.println("File::Logger: " + message);
}
}
// 使用责任链模式的不同记录器记录消息
public class ChainPatternDemo {
private static AbstractLogger getChainOfLoggers() {
AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
errorLogger.setNextLogger(fileLogger);
fileLogger.setNextLogger(consoleLogger);
return errorLogger;
}
public static void main(String[] args) {
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO, "这是一个信息日志信息。");
loggerChain.logMessage(AbstractLogger.DEBUG, "这是一个 debug 日志信息。");
loggerChain.logMessage(AbstractLogger.ERROR, "这是一个 error 日志信息。");
}
}
运行结果:
优点:
降低了请求对象与处理对象之间的耦合度。一个请求对象无须知道到底是哪一个对象理其请求以及链的结构。
可以根据需要增加新的请求处理类,满足开闭原则
当工作流程发生变化,可以动态地改变链内的成员或者调动它们的次序,也可动态地新增或者删除责任。
责任链简化了对象之间的连接。每个对象只需保持一个指向其后继者的引用,不需保持其他所有处理者的引用,这避免了使用众多的 if 或者if…else 语句。
责任分担。每个类只需要处理自己该处理的工作,不该处理的传递给下一个对象完成,明确各类的责任范围,符合类的单一职责原则。
缺点:
不能保证每个请求一定被处理。由于一个请求没有明确的接收者,所以不能保证它一定会被处理,该请求可能一直传到链的末端都得不到处理。
对比较长的职责链,请求的处理可能涉及多个处理对象,系统性能将受到一定影响。
职责链建立的合理性要靠客户端来保证,增加了客户端编程的复杂性,可能会由于职责链的错误设置而导致系统出错,如可能会造成循环调用。
分析如下请假条审批模块功能类图如何应用责任链模式设计?如何编写Java程序。
// 领导者是抽象处理者
abstract class Leader {
protected Leader next;
public void setNext(Leader next) {
this.next = next;
}
public Leader getNext() {
return next;
}
// 抽象处理请求的方法
public abstract void handleRequest(int LeaveDays);
}
// 具体处理者1:班主任
class ClassAdviser extends Leader {
@Override
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 2) { // 班主任可以批准最多2天的请假
System.out.println("班主任批准了 " + LeaveDays + " 天的请假。");
} else if (next != null) {
next.handleRequest(LeaveDays);
}
}
}
// 具体处理者2:系主任
class DepartmentHead extends Leader {
@Override
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 5) { // 系主任可以批准最多5天的请假
System.out.println("系主任批准了 " + LeaveDays + " 天的请假。");
} else if (next != null) {
next.handleRequest(LeaveDays);
}
}
}
// 具体处理者3:院长
class Dean extends Leader {
@Override
public void handleRequest(int LeaveDays) {
if (LeaveDays <= 10) { // 院长可以批准最多10天的请假
System.out.println("院长批准了 " + LeaveDays + " 天的请假。");
} else {
System.out.println("请假请求 " + LeaveDays + " 天被拒绝。");
}
}
}
// 客户端类
public class LeaveApprovalTest {
public static void main(String[] args) {
// 设置责任链
Leader teacher1 = new ClassAdviser();
Leader teacher2 = new DepartmentHead();
Leader teacher3 = new Dean();
teacher1.setNext(teacher2);
teacher2.setNext(teacher3);
// 发起请求
teacher1.handleRequest(8); // 这个请求将由院长处理
}
}
客户端类也可按如下方式书写:
public class LeaveApprovalTest {
private static Leader getChainOfLeaders() {
// 创建责任链
Leader classAdviser = new ClassAdviser();
Leader departmentHead = new DepartmentHead();
Leader dean = new Dean();
// 设置责任链
classAdviser.setNext(departmentHead);
departmentHead.setNext(dean);
// 返回链的起始点
return classAdviser;
}
public static void main(String[] args) {
Leader chainOfLeaders = getChainOfLeaders();
// 发起请求
chainOfLeaders.handleRequest(8); // 这个请求将由院长处理
}
}
班主任可以批准最多2天的请假,系主任可以批准最多5天的请假,院长可以批准最多10天的请假。如果有一个请求是请8天假,班主任会将它传递给系主任,系主任再传递给院长进行批准。如果请求超出了批准能力,就会被拒绝。
中介者模式是一种通过中介对象来封装若干对象之间的交互,实现对象之间的松耦合,并且可以独立地改变它们之间交互的设计模式。
在一些应用中,多个对象之间存在较复杂的网状交互关系。如果把这种’网状结构"改为“星形结构”,可降低它们之间的“耦合性”。这时只要找一个“中介者”来实现。
抽象中介者 (Mediator) : 提供了同事对象注册与转发同事对象信息的抽象方法。
具体中介者 (Concrete Mediator) :实现抽象中介者类,定义一个 List 来管理同事对象,协调各个同事角色之间的交互关系。
抽象同事类(Colleague) : 定义同事类的抽象方法,引用中介者对象,实现同事类的公共功能。
具体同事类 (Concrete Colleague) : 抽象同事类的实现者,当同事对象交互时由中介者对象负责转发之间的交互。
package mediator;
import java.util.*;
// 中介者模式
public class MediatorPattern {
public static void main(String[] args) {
Mediator md = new ConcreteMediator();
Colleague c1, c2;
c1 = new ConcreteColleague1();
c2 = new ConcreteColleague2();
md.register(c1);
md.register(c2);
c1.send();
System.out.println("---------------");
c2.send();
}
}
// 抽象中介者
abstract class Mediator {
public abstract void register(Colleague colleague);
public abstract void relay(Colleague cl); // 转发
}
// 具体中介者
class ConcreteMediator extends Mediator {
private List<Colleague> colleagues = new ArrayList<Colleague>();
public void register(Colleague colleague) {
if (!colleagues.contains(colleague)) {
colleagues.add(colleague);
colleague.setMedium(this);
}
}
public void relay(Colleague cl) {
for (Colleague ob : colleagues) {
if (!ob.equals(cl)) {
((Colleague) ob).receive();
}
}
}
}
// 抽象同事类
abstract class Colleague {
protected Mediator mediator;
public void setMedium(Mediator mediator) {
this.mediator = mediator;
}
public abstract void receive();
public abstract void send();
}
// 具体同事类1
class ConcreteColleague1 extends Colleague {
public void receive() {
System.out.println("具体同事类1收到请求。");
}
public void send() {
System.out.println("具体同事类1发出请求。");
mediator.relay(this); // 请求中介者转发
}
}
// 具体同事类2
class ConcreteColleague2 extends Colleague {
public void receive() {
System.out.println("具体同事类2收到请求。");
}
public void send() {
System.out.println("具体同事类2发出请求。");
mediator.relay(this); // 请求中介者转发
}
}
运行结果:
多个用户可以通过聊天室进行消息交流聊天室向所有的用户显示消息。
创建两个类 ChatRoom 和 User。
User 对象 使用 ChatRoom 对象的showMessage()方法来分享他们的消息。
MediatorPatternDemo演示类使用 User对象来显示他们之间的通信。
package MediatorPattern;
import java.util.Date;
// 聊天室类充当中介者
class ChatRoom {
public static void showMessage(User user, String message) {
System.out.println(new Date().toString() + " [" + user.getName() + "]: " + message);
}
}
// 用户类
class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public User(String name) {
this.name = name;
}
public void sendMessage(String message) {
ChatRoom.showMessage(this, message);
}
}
// 中介者模式演示
public class MediatorPatternDemo {
public static void main(String[] args) {
User robert = new User("Robert");
User john = new User("John");
robert.sendMessage("Hi! John!");
john.sendMessage("Hello! Robert!");
}
}
运行示例:
优点:
类之间各司其职,符合迪米特法则。
降低了对象之间的耦合性,使得对象易于独立地被复用。
将对象间的一对多关联转变为一对一的关联,提高系统的灵活性,使得系统易于维护和扩展。
缺点:
分析如下“房地产交流”模块功能类图如何应用中介者模式设计?给出Java程序。
import java.util.ArrayList;
import java.util.List;
// 中介者接口
interface Medium {
void register(Customer member);
void relay(String from, String ad);
}
// 房地产中介
class EstateMedium implements Medium {
private List<Customer> members = new ArrayList<>();
@Override
public void register(Customer member) {
if (!members.contains(member)) {
members.add(member);
member.setMedium(this);
}
}
@Override
public void relay(String from, String ad) {
for (Customer member : members) {
if (!member.getName().equals(from)) {
member.receive(from, ad);
}
}
}
}
// 客户类
abstract class Customer {
protected Medium medium;
protected String name;
public Customer(String name) {
this.name = name;
}
public abstract void send(String ad);
public abstract void receive(String from, String ad);
public String getName() {
return name;
}
public void setMedium(Medium medium) {
this.medium = medium;
}
}
// 卖方类
class Seller extends Customer {
public Seller(String name) {
super(name);
}
@Override
public void send(String ad) {
System.out.println("Seller [" + this.name + "] sends message: " + ad);
medium.relay(this.name, ad);
}
@Override
public void receive(String from, String ad) {
System.out.println("Seller [" + this.name + "] received message from " + from + ": " + ad);
}
}
// 买方类
class Buyer extends Customer {
public Buyer(String name) {
super(name);
}
@Override
public void send(String ad) {
System.out.println("Buyer [" + this.name + "] sends message: " + ad);
medium.relay(this.name, ad);
}
@Override
public void receive(String from, String ad) {
System.out.println("Buyer [" + this.name + "] received message from " + from + ": " + ad);
}
}
// 中介者模式演示
public class MediatorPattern {
public static void main(String[] args) {
Medium medium = new EstateMedium();
Customer seller = new Seller("Alice");
Customer buyer = new Buyer("Bob");
medium.register(seller);
medium.register(buyer);
seller.send("House for sale!");
buyer.send("Looking for a house!");
}
}
运行结果:
一、单选题
1.哪种设计原则要求面向接口编程,而不要面向实现编程??
A.开闭原则
B.里氏替换原则
C.依赖倒置原则
D.接口分离原则
2.哪种设计原则要求没有直接关系的类就不能直接相互调用?(B)
A.里氏替换原则
B.迪米特法则
C. 依赖倒置原则
D.开闭原则
3.下面哪个不是发现类的方法??
A. CRC方法
B.用例驱动法
C.头脑风暴
D.公共类模式法
4.子类组合来自超类的特征,并重载部分继承来的特征,该继承称为什么??
A.扩展继承
B.方便继承
C.限制继承
D.以上都不是
5.下面哪一个操作符用于定义条件片段??
A. opt
B. para
C. alt
D. loop
二、判断题
1.单例模式属于设计模式的行为模式类别。(×)
2.适配器模式可以解决不同模块的类接口转换问题。(√)
3.桥接模式是一种用于把抽象部分与实现部分解耦的设计模式。(√)
4.责任链模式要求请求发送者与多个请求处理者直接交互。(×)
5.中介者模式的动机用于降低多个对象之间存在较复杂的关系。(√)
6.处于相同状态的同类的不同对象对同一事件的反应往往是一样的,而处于不同状态的同一对象则对同一事件会做出不同反应。(√)
7.只要将包中元素的可见性设为公共的,则其他包就可以访问它。(×)
8.聚合与泛化都是面向对象系统支持功能复用的强大技术。(×)
9.在UML构件图中,需要定义消息来描述构件之间的联系。(×)
10.所有对象都通过类来描述,所有类都具有对象。(×)
补充:
6.处于相同状态的对象对同一事件具有同样方式的反应,所以当给定状态下的多个对象当接受到相同事件时会执行相同的动作,例如:当一个在线视频播放器处于"播放中"状态时,对于"暂停"按钮的点击事件,所有这类播放器对象都会执行相同的动作,即暂停当前视频。无论哪个播放器实例,只要它正在播放视频,点击"暂停"按钮都会导致视频停止播放。然而处于不同状态下的对象会通过不同的动作对同一事件做出不同的反应。例如,当自动答复机处于处理事务状态或空闲状态时会对取消键做出不同的反应。
7.虽然将类或成员的可见性设为公共(public)可以让其他包中的类访问这些元素,但这并不是唯一的条件。其他包中的类还需要正确地导入包含公共元素的包。
8.这道题网上搜出来都是对的,答案给的错,后面再看看吧。
10.所有对象都是由类来描述的,这是正确的;但不是所有类都具有对象实例。有些类可能从未被实例化,尤其是抽象类和工具类(可能只有静态方法和成员)。
三、填空题
(状态机图)通过对对象的各种状态建立模型来描述对象随时间变化的动态行为,并且它是以独立的对象为中心进行描述的。
在UML类图中,类用矩形图符来表示,这个矩形由3个部分组成,分别是类型名、(属性)和操作。
UML中的交互图包括顺序图和(通信图)。
UML中顺序图表示为二维图,纵向是对象,横向代表参与交互对象之间的(消息)。
状态机图由对象的状态和连接这些状态的(转换)组成。