一、实验目的
1、理解设计模式的基本思想;
2、理解并掌握常用的几种设计模式;
3、根据需求编写简单工厂设计模式;
4、根据需求编写适配器设计模式;
二、实验内容和步骤
1. 简单工厂模式实现计算器
请用简单工厂模式设计并编码实现一个计算器。工厂类根据键盘输入产生加、减、乘、除运算对象,并输出运算结果。贴出代码及运行截图
💖 SimpleFactoryDemo.java
import java.util.Scanner;
public class SimpleFactoryDemo
{
public static void main(String[] args)
{
CalculatorSimpleFactory factory = new CalculatorSimpleFactory();
// 测试
Scanner sc = new Scanner(System.in);
while (true)
{
menu();
int a = 0, b = 0;
String type = null;
try
{
a = sc.nextInt();
type = sc.next();
b = sc.nextInt();
Calculator calculator = CalculatorSimpleFactory.getCalculator(type, a, b);
double ans = calculator.calculate();
System.out.println(ans);
} catch (Exception e)
{
String msg = e.getMessage();
sc = new Scanner(System.in);
if (msg != null)
System.err.println(msg);
else
System.err.println("输入格式有误,请重新输入!!");
continue;
}
}
}
private static void menu()
{
System.out.println("请按格式输入: 【操作数1 运算符 操作数2】中间空格隔开");
}
}
class CalculatorSimpleFactory
{
/**
* 根据计算类型和操作数创建相应的计算器对象
*
* @param calculateType 计算类型,如"+", "-", "*", "/"
* @param operator1 第一个操作数
* @param operator2 第二个操作数
* @return 对应的计算器对象
*/
public static Calculator getCalculator(String calculateType, double operator1, double operator2)
{
Calculator calculator = null;
switch (calculateType)
{
case "+":
case "加":
calculator = new AddCalculator(operator1, operator2);
break;
case "-":
case "减":
calculator = new SubtractCalculator(operator1, operator2);
break;
case "*":
case "×":
case "乘":
calculator = new MultiplyCalculator(operator1, operator2);
break;
case "/":
case "÷":
case "除":
calculator = new DivideCalculator(operator1, operator2);
break;
default:
throw new RuntimeException("暂不支持此计算功能!");
}
return calculator;
}
}
/**
* 计算器抽象类,定义了计算器的基本属性和方法
*/
abstract class Calculator
{
double operator1;
double operator2;
public Calculator(double operator1, double operator2)
{
super();
this.operator1 = operator1;
this.operator2 = operator2;
}
/**
* 抽象方法,用于计算具体的运算结果
*
* @return 运算结果
*/
public abstract double calculate();
}
/**
* 加法计算器类,继承自计算器抽象类,实现了加法运算
*/
class AddCalculator extends Calculator
{
public AddCalculator(double operator1, double operator2)
{
super(operator1, operator2);
}
@Override
public double calculate()
{
return super.operator1 + super.operator2;
}
}
/**
* 减法计算器类,继承自计算器抽象类,实现了减法运算
*/
class SubtractCalculator extends Calculator
{
public SubtractCalculator(double operator1, double operator2)
{
super(operator1, operator2);
}
@Override
public double calculate()
{
return super.operator1 - super.operator2;
}
}
/**
* 乘法计算器类,继承自计算器抽象类,实现了乘法运算
*/
class MultiplyCalculator extends Calculator
{
public MultiplyCalculator(double operator1, double operator2)
{
super(operator1, operator2);
}
@Override
public double calculate()
{
return super.operator1 * super.operator2;
}
}
/**
* 除法计算器类,继承自计算器抽象类,实现了除法运算
*/
class DivideCalculator extends Calculator
{
public DivideCalculator(double operator1, double operator2)
{
super(operator1, operator2);
}
@Override
public double calculate()
{
if (super.operator2 == 0)
throw new RuntimeException("除数不能为 0!");
return super.operator1 / super.operator2;
}
}
🐷 运行结果
2. 适配器模式
这段代码演示了适配器模式的一个常见用法,即通过继承或实现接口来提供一个统一的接口,即使底层的实现可能并不完整或不完全符合预期。在实际应用中,适配器模式通常用于将一个类的接口转换成客户端期望的另一个接口,使得原本由于接口不兼容而不能一起工作的类可以一起工作。
- 接口不兼容:有人只会中文,有人只会英语,不兼容
- 接口转换:实现翻译,自定义实现 中译英、法、日 接口
💖 AdapterDemo.java
// 适配器模式演示代码
public class AdapterDemo {
public static void main(String[] args) {
// 创建一个Speaker对象,该对象实现了Translate接口
Speaker speaker = new Speaker() {
@Override
public void toFrench() {
System.out.println("翻译成法语");
}
@Override
public void toEnglish() {
System.out.println("翻译成英语");
}
// 注意:这里没有实现toJapanese方法,因此会调用父类的实现
// 如果父类也没有实现,那么会抛出异常
@Override
public void toJapanese() {
// 这里可以添加具体的实现,或者抛出异常
System.err.println("暂未实现");
}
};
// 调用Speaker对象的toEnglish方法
speaker.toEnglish();
// 调用Speaker对象的toFrench方法
speaker.toFrench();
// 调用Speaker对象的toJapanese方法
speaker.toJapanese();
}
}
// 定义一个抽象类Speaker,它实现了Translate接口
abstract class Speaker implements Translate {
// 实现Translate接口的toEnglish方法,但这里没有具体实现
public void toEnglish() {
System.err.println("暂未实现");
}
// 实现Translate接口的toFrench方法,但这里没有具体实现
public void toFrench() {
System.err.println("暂未实现");
}
// 实现Translate接口的toJapanese方法,但这里没有具体实现
public void toJapanese() {
System.err.println("暂未实现");
}
}
// 定义一个Translate接口,包含三个方法:toEnglish, toFrench, toJapanese
interface Translate {
// 将内容翻译成英语
public void toEnglish();
// 将内容翻译成法语
public void toFrench();
// 将内容翻译成日语
public void toJapanese();
}
🐷 运行结果
翻译成英语
翻译成法语
暂未实现
3. 单例模式
💖 SingletonDemo.java
class Singleton
{
// 私有静态变量,用于保存类的唯一实例
private static Singleton instance = null;//懒汉式单例
// 在类加载时就创建实例,确保全局只有一个实例
// 饿汉式单例( getInstance() 方法里无需 new 创建新的实例对象)
// private static final Singleton instance = new Singleton();
// 私有构造方法,防止外部通过new创建多个实例
private Singleton()
{
}
// 公共静态方法,提供全局访问点
public static Singleton getInstance()
{
// 双重检查锁定,确保线程安全
if (instance == null)
{
synchronized (Singleton.class)
{
if (instance == null)
{
instance = new Singleton();
}
}
}
return instance;
}
// 示例方法,可以在这里添加需要单例执行的业务逻辑
public void dSsomething()
{
System.out.println("singleton is doing something.");
}
}
public class SingletonDemo
{
public static void main(String[] args)
{
// 通过geIinstance方法获Ssingleton的唯一实例
Singleton singleton = Singleton.getInstance();
singleton.dSsomething();
}
}
运行结果
singleton is doing something.
💖 EnumSingletonDemo.java
由于枚举类型的实例在类加载时就被初始化,因此可以确保 Singleton 类只有一个实例。枚举的构造函数是私有的,所以不能从类的外部创建枚举的实例。
enum SingletonEnum
{
INSTANCE; // 唯一的枚举实例
// 示例方法,可以在这里添加需要单例执行的业务逻辑
public void doSomething()
{
System.out.println("SingletonEnum is doing something.");
}
}
public class EnumSingletonDemo
{
public static void main(String[] args)
{
// 直接通过枚举类型调用方法
SingletonEnum.INSTANCE.doSomething();
}
}
运行结果
SingletonEnum is doing something.
三、总结
简单工厂模式
问题: 违反开闭原则,工厂类职责重。
解决: 使用反射、配置文件或工厂方法模式。
小结: 适用于产品类少,创建逻辑简单。复杂度高时,可采用工厂方法模式。
适配器模式
问题: 代码复杂度增加,性能问题。
解决: 使用对象组合、代理模式、泛型。
小结: 解决接口不兼容问题,但可能增加复杂度和性能开销。
单例模式
问题: 全局访问点,线程安全问题。
解决: 使用枚举、双重检查锁定、静态内部类。
小结: 确保类唯一实例,提供全局访问点。枚举实现简单且线程安全。