设计模式简要总结
用于期末考试复习
策略模式
使用场景
当我们需要用户传入的不同参数来决定不同的方法策略时,可以用到此模式。 根据不同的情况来选择不同的策略
用云顶之奕举例子: 我们可以根据不同的海克斯选择不同的策略去选择阵容。
代码实现
策略接口
public interface Lineup {
/**
* 挑选阵容
*/
void selectLineup();
}
阵容具体实现
public class DuelMaster implements Lineup{
@Override
public void selectLineup() {
System.out.println("八决斗灭魂劫嗷嗷乱杀");
}
}
public class DefendOfStar implements Lineup{
@Override
public void selectLineup() {
System.out.println("无所谓,我星守岩雀会出手!");
}
}
public class MoDaoTuan implements Lineup{
@Override
public void selectLineup() {
System.out.println("嘿,这里是老八魔盗团!");
}
}
玩家类
public class Player {
private Lineup lineup;
Player(Lineup lineup){
this.lineup = lineup;
}
public void action(){
lineup.selectLineup();
}
}
main
public class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(new BufferedInputStream(System.in));
Player player;
System.out.println("输入你选择的海克斯");
while(true){
String hex = scanner.nextLine();
switch (hex){
case "地下魔盗团之魂" :
player = new Player(new MoDaoTuan());
break;
case "决斗大师之魂" :
player = new Player(new DuelMaster());
break;
case "珠光莲花" :
player = new Player(new DefendOfStar());
break;
default:
throw new IllegalStateException("Unexpected value: " + hex);
}
player.action();
}
}
}
运行结果
容易困惑的问题
他与工厂模式的区别是什么
策略模式是根据行为设计的模式 他针对的是策略的封装,用户可以知道全部的策略。
工厂模式是根据创建对象设计的模式,他是针对于对象的创建,便于统一资源管理,相关对象的创建由工厂类处理,不必暴露给用户
uml图
访问者模式
使用场景
在一个相对稳定的数据结构中,封装一些对于数据结构中元素的操作,从而不改变这个数据结构。
依旧是云顶的例子哈,在每一场游戏中,一个人的棋盘的元素是相对稳定的,现在假设只有经济和等级(其他元素先省略) 我作为访问者和其他人作为访问者又是不一样的
代码实现
public interface Visitor {
void visit(Level level);
void visit(Money money);
}
public class Owner implements Visitor{
@Override
public void visit(Level level) {
System.out.println("你现在等级是"+level.getNum()+"级,还差"+level.getNeed()+"经验升级,卷死老哥们!");
}
@Override
public void visit(Money money) {
System.out.println("你现在有"+money.getNum()+"块钱,备战席卖掉卡利息啊!");
}
}
public class Other implements Visitor{
@Override
public void visit(Level level) {
System.out.println("这货现在"+level.getNum()+"级了,卷闷了");
}
@Override
public void visit(Money money) {
System.out.println("他现在保底有"+money.getStar()+"0块钱,经济酱紫高?");
}
}
public interface GameItem {
void accept(Visitor visitor);
}
public class Level implements GameItem{
/**
* 等级
*/
private int num;
/**
* 还差多少升下一等级
*/
private int need;
public Level(int num, int need) {
this.num = num;
this.need = need;
}
public int getNum() {
return num;
}
public int getNeed() {
return need;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Money implements GameItem {
/**
* 每十块钱地图侧边就有一颗星
*/
private int star;
/**
* 具体数值
*/
private int num;
public Money(int star, int num) {
this.star = star;
this.num = num;
}
public int getStar() {
return star;
}
public int getNum() {
return num;
}
@Override
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public class Chessboard {
private List<GameItem> itemList = new ArrayList<>();
Chessboard(){
itemList.add(new Level(5,10));
itemList.add(new Money(5,52));
}
public void show(Visitor visitor){
for(GameItem g:itemList){
g.accept(visitor);
}
}
}
public class Main {
public static void main(String[] args) {
//初始化一下棋盘
Chessboard chessboard = new Chessboard();
//我自己看棋盘
System.out.println("我自己访问");
System.out.println("----------------");
chessboard.show(new Owner());
System.out.println("----------------");
//别人看棋盘
System.out.println("别人访问");
System.out.println("----------------");
chessboard.show(new Other());
System.out.println("----------------");
}
}
运行结果
容易困惑的问题
并不知道visit方法和accept方法实际上是干什么用的只有模模糊糊的概念。
在visitor接口中,定义了好多visit方法。每一个方法都是针对某个具体元素的访问。
上面说过,这个数据结构是相对稳定的,也就是说,我们后续不需要对这个接口在做更改,便于编码
而accept方法则是表示这个元素接收的是哪个访问者的访问,根据不同访问者提供不同的作用
uml图
建造者模式
使用场景
当我们需要构建一个相对复杂的对象时,我们可以把他的构建与表示分离,从而优化设计。
当类的构造函数的参数很多时,并且不全是必要属性,我们就可以考虑使用建造者模式。
一辆汽车有轮子,邮箱和车身,我们可以构建奔驰汽车和宝马汽车,使用建造者模式实现
代码实现
定义一个汽车
public class CarProduct {
private String wheel;
private String oilBox;
private String body;
public void setWheel(String wheel) {
this.wheel = wheel;
}
public void setOilBox(String oilBox) {
this.oilBox = oilBox;
}
public void setBody(String body) {
this.body = body;
}
public void show(){
System.out.println("1."+wheel+" 2."+oilBox+" 3."+body);
}
}
builder类
public abstract class Builder {
protected CarProduct carProduct = new CarProduct();
public abstract void buildWheel();
public abstract void buildOilBox();
public abstract void buildBody();
public CarProduct getResult(){
return carProduct;
}
}
具体的builder
public class BMWBuilder extends Builder{
@Override
public void buildWheel() {
carProduct.setWheel("BMW的轮胎");
}
@Override
public void buildOilBox() {
carProduct.setOilBox("BMW的油箱");
}
@Override
public void buildBody() {
carProduct.setBody("BMW的车身");
}
}
public class BenZBuilder extends Builder{
@Override
public void buildWheel() {
carProduct.setWheel("BenZ的轮胎");
}
@Override
public void buildOilBox() {
carProduct.setOilBox("BenZ的油箱");
}
@Override
public void buildBody() {
carProduct.setBody("BenZ的车身");
}
}
director
public class Director {
private Builder builder;
Director(Builder builder){
this.builder = builder;
}
public CarProduct construct(){
builder.buildWheel();
builder.buildOilBox();
builder.buildBody();
return builder.getResult();
}
}
客户端
public class Client {
public static void main(String[] args) {
Builder bmwBuilder = new BMWBuilder();
Builder benZBuilder = new BenZBuilder();
Director director = new Director(bmwBuilder);
CarProduct construct = director.construct();
construct.show();
director = new Director(benZBuilder);
CarProduct construct1 = director.construct();
construct1.show();
}
}
另一种实现方式
public class Car {
private final String wheel;
private final String oilBox;
private final String body;
private Car(Builder builder){
this.wheel = builder.wheel;
this.oilBox = builder.oilBox;
this.body = builder.body;
}
public static class Builder{
private String wheel;
private String oilBox;
private String body;
public Builder(){
}
public Builder setWheel(String wheel) {
this.wheel = wheel;
return this;
}
public Builder setOilBox(String oilBox) {
this.oilBox = oilBox;
return this;
}
public Builder setBody(String body) {
this.body = body;
return this;
}
public Car build(){
return new Car(this);
}
}
public void show(){
System.out.println("1."+wheel+" 2."+oilBox+" 3."+body);
}
}
调用方式我觉得还挺优雅
public class Client {
public static void main(String[] args) {
Car car = new Car.Builder()
.setOilBox("BMW的油箱")
.setBody("BenZ的车身")
.setWheel("中国制造的轮胎")
.build();
car.show();
}
}
第二种的实现方式经常可以在一些框架当中见到
uml图
适配器模式
使用场景
类似于一个转接头吧,现在很多手机都没有耳机孔了,需要一个适配器来转换typeC和耳机孔。
代码实现
public class EarChicken {
public void listenMusic(){
System.out.println("有线耳机已经连接");
}
}
public interface HuaWeiPhone {
public void listen();
}
public class Adepter implements HuaWeiPhone{
private EarChicken earChicken;
Adepter(EarChicken earChicken){
this.earChicken = earChicken;
}
@Override
public void listen() {
earChicken.listenMusic();
}
}
uml图
挺简单的不多赘述
观察者模式
使用场景
首先有两方,一个是观察者,一个是被观察者,当被观察者发生变化时,观察者要做出相应改变。
挺绕的其实,要分清观察者和被观察者。 例子使用学校实验课说过的,商品如果价格和名字发生改变,则通知会员。
代码实现
首先定义观察者接口
public interface Observer {
//这个方法就是观察者如果观察到变化后所做出的改变
void update(String name,Double price);
}
然后定义被观察者 因为一个被观察者可以由多个观察者观察,因此需要用list存储观察者
public interface Subject {
void registerObserver(Observer observer);
void removeObserver(Observer observer);
void notifyObserver();
}
被观察者的具体实现
public class ProductSubject implements Subject{
private List<Observer> observers;
private String name;
private Double price;
ProductSubject(){
observers = new ArrayList();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
}
@Override
public void notifyObserver() {
for(Observer o:observers){
o.update(name,price);
}
}
public void setProduct(String name,Double price){
this.name = name;
this.price = price;
//当元素改变时,通知观察者
notifyObserver();
}
}
观察者的具体实现
public class ConcreteObserver implements Observer{
private String name;
private Double price;
private Subject subject;
ConcreteObserver(Subject subject){
this.subject = subject;
subject.registerObserver(this);
}
@Override
public void update(String name, Double price) {
this.name = name;
this.price = price;
System.out.println("接收到信息,并给你处理\n" +
"商品名称为"+name+" 价格为"+price);
}
}
可能会迷惑的
一定要分清观察者和被观察者,被观察者的类一定要设计三个方法,一个是添加观察者,一个是删除,一个是数据更新后提醒观察者。 而观察者中,有一个方法是update,就是用于观察到对象改变后所要进行的操作。
在移动应用开发中,经常可以见到,当我们对RecycleView的元素 操作发生变化时,我们会使用到notifyObserver(),这里就是用到了观察者模式。
uml图
桥接模式
使用场景
就跟他名字一样,如果我们想要的一个类中,有两个以上的元素可以独立扩展就可以将他拆分出来,需要的时候,在使用桥接模式拼在一起。
例子就用实验课上的,咖啡分大中小杯,可以加糖、奶之类的元素,最后生成一个我们想要的咖啡
代码实现
咖啡接口
public interface Coffee {
void add(Thing thing);
void drink();
}
咖啡料的接口
public interface Thing {
void add();
}
具体咖啡实现(只列一种)
public class SmallCoffee implements Coffee{
private Thing thing;
@Override
public void add(Thing thing) {
this.thing = thing;
}
@Override
public void drink() {
System.out.print("我是小杯咖啡");
thing.add();
}
}
具体咖啡料实现(只列一种)
public class Milk implements Thing{
@Override
public void add() {
System.out.println("加了牛奶。");
}
}
这边结合了简单工厂模式制作了一个客户端
public class Factory {
public Thing getThing(int type){
switch (type){
case 1 : return new Milk();
case 2 : return new Sugar();
case 3 : return new Lemon();
default: return null;
}
}
public Coffee getCoffee(int type){
switch (type){
case 1 : return new JorumCoffee();
case 2 : return new MediumCoffee();
case 3 : return new SmallCoffee();
default: return null;
}
}
}
public class Client {
public static void main(String[] args) {
Factory factory = new Factory();
Scanner scanner = new Scanner(System.in);
while(true){
System.out.println("选择你想喝的咖啡吧!\n" +
"1、大杯\n" +
"2、中杯\n" +
"3、小杯");
Integer integer = Integer.parseInt(scanner.nextLine());
Coffee coffee = factory.getCoffee(integer);
System.out.println("加点什么?\n" +
"1、牛奶\n" +
"2、糖\n" +
"3、柠檬");
coffee.add(factory.getThing(Integer.parseInt(scanner.nextLine())));
coffee.drink();
}
}
}
容易困惑的
为什么使用桥接模式,因为如果上面的例子我要单独设置一个类去表示的话,我需要写3*3=9个类去分别代表不同的咖啡。 但如果我把它拆分开,我就只写了6个类,工作量大大降低。
uml图
装饰模式
使用场景
叠buff知道吧,就是给一个基本类增加几个特殊的属性,从而完成不同的工作。
继续是实验课的例子,喜羊羊吃苹果。 通过吃不同的苹果获得不同buff
代码实现
羊,基本类
public class Sheep {
private Integer blood;
public Integer getBlood(){
return blood;
}
public void show(){
System.out.println("我是一只🐏");
}
public Sheep(Integer blood) {
this.blood = blood;
}
public boolean hurt(){
this.blood--;
if (blood==0){
return false;
}
return true;
}
}
装饰羊,后面的buff羊是通过继承装饰羊得以实现,不直接继承基本羊!!
public class DecoratorSheep extends Sheep{
protected Sheep sheep;
public DecoratorSheep(Sheep sheep) {
super(sheep.getBlood());
this.sheep = sheep;
}
@Override
public void show() {
if (sheep!=null){
sheep.show();
}
}
}
buff羊(只给一个)
public class RedSheep extends DecoratorSheep{
public RedSheep(Sheep sheep) {
super(sheep);
}
@Override
public void show() {
super.show();
System.out.println("我还吃了红苹果,有保护罩");
}
}
客户端
public class Client {
public static void main(String[] args) {
System.out.println("游戏开始\n" +
"请选择操作\n" +
"1.被狼咬\n" +
"2.吃红苹果\n" +
"3.吃绿苹果\n" +
"4.吃黄苹果\n" +
"5.不想玩啦,退出!");
Scanner scanner = new Scanner(System.in);
Sheep sheep = new Sheep(5);
DecoratorSheep gameSheep = new DecoratorSheep(sheep);
boolean flag = true;
while (flag){
int type = scanner.nextInt();
switch (type){
case 1: {
if(!gameSheep.hurt()){
System.out.println("你死了");
flag = false;
}
System.out.println("还剩"+gameSheep.getBlood()+"血!");
break;
}
case 2: {
gameSheep = new RedSheep(gameSheep);
gameSheep.show();
break;
}
case 3: {
gameSheep = new GreenSheep(gameSheep);
gameSheep.show();
break;
}
case 4: {
gameSheep = new YellowSheep(gameSheep);
gameSheep.show();
break;
}
default:{
System.out.println("游戏结束,期待相遇");
flag = false;
}
}
}
}
}
容易困惑的
为什么buff羊不直接继承基本羊,要另外设计一个装饰羊来继承。 在基础羊中,我们需要通过构造函数维护基本羊的一些属性,在装饰模式中,装饰羊的构造方法是我们特别设计的,后续的buff羊可以直接利用这个构造方法进行装饰。