2023/7/15·一些设计模式(Java)
1 · 单例模式
单例模式 指某一个类只能实例化一个对象的设计模式,单例模式分为 懒汉式 和 饿汉式,顾名思义,懒汉式 不到最后一刻是不会初始化对象的,而 饿汉式 的创建对象和初始化对象都会在第一时间完成。
public class Student {
//单例模式 饿汉式
static Student student = new Student(); //创建对象即初始化
private Student() { //私有化构造,防止外部创建对象
}
public static Student getStudent() { //获取对象的方法
return student;
}
public void study() {
System.out.println("学习");
}
}
public class Student {
//单例模式 懒汉式
static Student student;
private Student() {
}
public static Student getStudent() {
if (student == null)
student = new Student(); //需要获取对象时才初始化
return student;
}
public void study() {
System.out.println("学习");
}
}
2 · 简单工厂模式
简单工厂模式 又称 静态工厂模式,不同于 单例模式,工厂模式一般适用于创建对象的种类较多,可以归属于同一体系下时,可以考虑使用工厂模式来进行整个继承体系对象的同一创建,这样就不需要给每个单独的子类提供一个创建的方法。
这里创建了一个 Game 接口
public interface Game {
public void getGameName();
}
再创建两个类 EldenRing 和 DevilMayCry 实现 Game 接口
public class EldenRing implements Game {
private String name = "艾尔登法环";
@Override
public void getGameName() {
System.out.println(name);
}
}
public class DevilMayCry implements Game {
private String name = "鬼泣";
@Override
public void getGameName() {
System.out.println(name);
}
}
最后创建 Steam 类,也就是“工厂”
public class Steam {
//工厂模式
public static Game getGame(String name) { //接受游戏名参数,返回接口类型的对象
if ("艾尔登法环".equals(name)) {
return new EldenRing();
} else if ("鬼泣".equals(name)) {
return new DevilMayCry();
}
return null;
}
}
测试一下,控制台成功输出艾尔登法环的getGameName()方法
public class test {
public static void main(String[] args) {
EldenRing eldenRing = (EldenRing) Steam.getGame("艾尔登法环");
eldenRing.getGameName();
//艾尔登法环
}
}
3 · 静态代理模式
代理模式包含如下角色:
抽象主题(Subject):通过接口或抽象类声明业务方法。
真实主题 (Real Subject):实现了抽象主题中的具体业务,是实施代理的目标对象,即代理对象所代表的真实对象,是最终要引用的对象。
代理(Proxy):提供了与真实主题相同的接口,其内部含有对真实主题的引用,可以访问、控制或拓展真实主题的功能。
这里创建一个People接口,这是抽象主题。
public interface People {
//人都会交流
public void talk();
}
再创建Student类和Gamer类实现People接口,各自重写talk() 方法,这里Gamer是代理,所以在Gamer类中添加一个People属性,新建一个参数为People接口的构造器,构造器用于接收真实主题的对象,再在talk()方法内调用真实主题对象的talk方法,这就形成了代理模式。
public class Student implements People{
@Override
public void talk() {
System.out.println("学生说话");
}
}
public class Gamer implements People {
private People p;
public Gamer() {
}
//初始化时,接受代理人
public Gamer(People p) {
this.p = p;
}
@Override
public void talk() {
p.talk(); //执行代理人自己的方法
System.out.println("玩家讲话");
}
}
这里简单运行一下,可以看到以Student以Gamer的身份同事调用了两个talk()方法
public class test {
public static void main(String[] args) {
Gamer gamer = new Gamer(new Student());
gamer.talk();
}
}
// 学生说话
// 玩家讲话
4 · 适配器模式(类适配器)
适配器模式 包含如下角色:
目标角色(Target),被转换后的目标接口。
源角色(Adaptee),需要被转换的接口。
适配器(Adapter),负责将Adaptee转换为Target。
创建目标角色:
public interface GameController { //手柄
String outControllerSignal(); //输出手柄信号
}
源角色:
public class KeyboardMouse { //键鼠
public String outKMSignal(){
return "键鼠信号";
}
}
适配器:
public class Translator extends KeyboardMouse implements GameController{ //键鼠转换器+
@Override
public String outControllerSignal() {
String signal = super.outKMSignal(); //获得键鼠信号
String finalSignal = signal +"(已转换为手柄信号)"; //适配过程
System.out.println("已将"+signal+"转换为手柄信号");
return finalSignal;
}
}
测试,获得了转换之后的键鼠信号
public class test {
public static void main(String[] args) {
Translator translator = new Translator();
System.out.println(translator.outControllerSignal());
//已将键鼠信号转换为手柄信号
//键鼠信号(已转换为手柄信号)
}
}
5 · 原型模式
原型模式通过对Object类的clone() 方法重写来实现对象的重复创建,用于大量创建重复对象,而不需要指定细节(属性、方法等等)。
这里用星战的例子创建一个克隆人士兵类(CloneTrooper) ,实现Cloneable 接口,才能拥有复制的能力。
还有用于基因原型的人类(Human) 。
//克隆士兵类
public class CloneTrooper implements Cloneable { //克隆人士兵
private Human geneticPrototype; //基因原型
public CloneTrooper() {
}
public CloneTrooper(Human geneticPrototype) {
this.geneticPrototype = geneticPrototype;
}
public void execute(int num) { //执行命令的方法
System.out.println("执行" + num + "号密令");
}
//重写clone方法,实现对原型的复制
@Override
protected Object clone() {
CloneTrooper cloneTrooper = null;
try {
cloneTrooper = (CloneTrooper) super.clone();
} catch (Exception e) {
e.printStackTrace();
}
return cloneTrooper;
}
public Human getGeneticPrototype() {
return geneticPrototype;
}
public void setGeneticPrototype(Human geneticPrototype) {
this.geneticPrototype = geneticPrototype;
}
}
//人类
public class Human {
private String name;
public Human(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
测试,创建基因原型詹戈菲特,创建第一个克隆人士兵,能够执行拥有的方法;再用clone() 方法克隆2号和3号克隆人士兵,分别执行66号密令和原型及其哈希码,可以看到原型都是同一个对象,省去了繁琐的初始化对象操作。
public class test {
public static void main(String[] args) {
Human JangoFett = new Human("Jango Fett"); //创建基因原型
CloneTrooper trooper1 = new CloneTrooper(JangoFett); //复制第一个克隆士兵
trooper1.execute(66); //执行66号密令
System.out.println("基因原型:"+trooper1.getGeneticPrototype().getName()+" 哈希码:"+trooper1.getGeneticPrototype().hashCode());
CloneTrooper trooper2 = (CloneTrooper) trooper1.clone(); //实际上克隆人都是由基因克隆而不是第一个克隆人的基因,这里就不忠于原著了
trooper2.execute(66);
System.out.println("基因原型:"+trooper2.getGeneticPrototype().getName()+" 哈希码:"+trooper2.getGeneticPrototype().hashCode());
CloneTrooper trooper3 = (CloneTrooper) trooper1.clone();
trooper2.execute(66);
System.out.println("基因原型:"+trooper3.getGeneticPrototype().getName()+" 哈希码:"+trooper3.getGeneticPrototype().hashCode());
//执行66号密令
//基因原型:Jango Fett 哈希码:460141958
//执行66号密令
//基因原型:Jango Fett 哈希码:460141958
//执行66号密令
//基因原型:Jango Fett 哈希码:460141958
}
}