设计模式---05.访问者模式

访问者模式

访问者模式是一种对象和对象的访问者分开的一种设计模式,在一个对象稳定的情况下,使用访问者模式可以更好的扩展对数据的访问。 相当于是我们在对象里面安插了一个“眼”,这个眼能够被外面实现,然后能拿到当前对象的各个属性。

举个例子

组装一台电脑,对于组装的对于组装者来说,只关心一个电脑零件构成(CPU,内存,鼠标键盘)。而对于电脑的消费者,关心的是电脑各个零件的价格以及总价。 而对于有些人来说对于,可能只关心电脑各个零件的重要性以及核心程度。综上所述我们操作的对象是一个电脑,对象是不变的,电脑的访问者来说是不同的,他们从不同的维度来分析这个电脑的属性。下面我们就用类图来表示访问者模式的大概结构:

访问者模式

对于访问者模式来说有以下几个实现步骤:

  1. 定义一个对象(可以是一个基类,也可是其他)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class ComputerPartBase   {
    private final String partName;
    private final int coreLevel;
    private final double price;

    public ComputerPartBase(String partName, int coreLevel, double price) {
    this.partName = partName;
    this.coreLevel = coreLevel;
    this.price = price;
    }

    public String getPartName() {
    return partName;
    }

    public int getCoreLevel() {
    return coreLevel;
    }

    public double getPrice() {
    return price;
    }

    }

  2. 定义一个接口,实现”插眼”的约束

    1
    2
    3
     public interface ComputerVisitor {
    public void accept(ComputerPartVisitor computerPartVisitor);
    }
  3. 对象继承”眼“,实现方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
      public class ComputerPartBase implements ComputerVisitor {

    //.....

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {

    }
    }
  4. 各个零件的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
     public class CPU  extends ComputerPartBase {
    public CPU() {
    super("CPU", 10,2000.00d);
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }

    public class Keyboard extends ComputerPartBase implements ComputerVisitor {
    public Keyboard() {
    super("keyboard", 1, 10);
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }

    public class Memery extends ComputerPartBase implements ComputerVisitor {
    public Memery() {
    super("memery", 8, 200d);
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }

    public class Monitor extends ComputerPartBase implements ComputerVisitor {
    public Monitor() {
    super("monitor", 2, 800);
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }

    public class Mouse extends ComputerPartBase implements ComputerVisitor {
    public Mouse() {
    super("mouse", 2, 100);
    }

    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }

  5. 真正的”眼“的接口

    1
    2
    3
    4
    5
    6
    7
    8
    9

    public interface ComputerPartVisitor {
    public void visit(CPU cpu);
    public void visit(Memery memery);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
    }

  6. 访问者通过实现来获取数据

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    //电脑的组成
    public class ComputerPartStrutchNameVisitor implements ComputerPartVisitor {

    private List<String> partSet=new ArrayList<>();
    @Override
    public void visit(CPU cpu) {
    partSet.add(cpu.getPartName());
    }

    @Override
    public void visit(Memery memery) {
    partSet.add(memery.getPartName());

    }

    @Override
    public void visit(Mouse mouse) {
    partSet.add(mouse.getPartName());

    }

    @Override
    public void visit(Keyboard keyboard) {
    partSet.add(keyboard.getPartName());

    }

    @Override
    public void visit(Monitor monitor) {
    partSet.add(monitor.getPartName());

    }

    public String getNeedPart(){
    return partSet.stream().collect(Collectors.joining(","));
    }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37

    //电脑的组装价格
    public class ComputerPartPriceVisitor implements ComputerPartVisitor {

    private double price = 0d;

    @Override
    public void visit(CPU cpu) {
    price += cpu.getPrice();
    }

    @Override
    public void visit(Memery memery) {
    price += memery.getPrice();

    }

    @Override
    public void visit(Mouse mouse) {
    price += mouse.getPrice();
    }

    @Override
    public void visit(Keyboard keyboard) {
    price += keyboard.getPrice();

    }

    @Override
    public void visit(Monitor monitor) {
    price += monitor.getPrice();
    }
    public double getPrice(){
    return price;
    }
    }

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    //获得电脑的核心等级
    public class ComputerPartCoreLevelVisitor implements ComputerPartVisitor {

    private List<String> levelList = new ArrayList<>();

    @Override
    public void visit(CPU cpu) {

    levelList.add("CPU:"+cpu.getCoreLevel());
    }

    @Override
    public void visit(Memery memery) {
    levelList.add("Memery:"+memery.getCoreLevel());
    }

    @Override
    public void visit(Mouse mouse) {
    levelList.add("Mouse:"+mouse.getCoreLevel());
    }

    @Override
    public void visit(Keyboard keyboard) {
    levelList.add("Keyboard:"+keyboard.getCoreLevel());
    }

    @Override
    public void visit(Monitor monitor) {
    levelList.add("Monitor:"+monitor.getCoreLevel());
    }
    public String getCoreLevel(){
    return levelList.stream().collect(Collectors.joining(","));
    }
    }

  7. 调用的实现

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class AppMain {
    public static void main(String[] args) {
    Computer computer = new Computer();
    ComputerPartStrutchNameVisitor computerPartVisitor = new ComputerPartStrutchNameVisitor();
    computer.accept(computerPartVisitor);
    System.out.println("组装一个电脑需要零件:" + computerPartVisitor.getNeedPart());

    ComputerPartPriceVisitor computerPartPriceVisitor = new ComputerPartPriceVisitor();
    computer.accept(computerPartPriceVisitor);
    System.out.println("组装一个电脑需要Money:" + computerPartPriceVisitor.getPrice());

    ComputerPartCoreLevelVisitor computerPartCoreLevelVisitor = new ComputerPartCoreLevelVisitor();
    computer.accept(computerPartCoreLevelVisitor);
    System.out.println("电脑硬件的核心优先级为:" + computerPartCoreLevelVisitor.getCoreLevel());
    }
    }

输出的结果为:

1
2
3
组装一个电脑需要零件:CPU,memery,monitor,keyboard,mouse
组装一个电脑需要Money:3110.0
电脑硬件的核心优先级为:CPU:10,Memery:8,Monitor:2,Keyboard:1,Mouse:2
阅读更多

设计模式--04.装饰者模式

在23种设计模式中,装饰者模式在游戏开发的过程中,使用的很是频繁。因为这个设计模式,把所有的业务的逻辑封装的对应的实体类中,从而为主流程减负了。首先看下一个应用场景

装饰者模式的应用

我们都知道有一款经典游戏90坦克,这个游戏中,玩家坦克来操作坦克打击AI敌人,在没打死一个红色坦克就会掉下来一个装备,这个装备可以提升移动速度,增加攻击力。

我们首先定义玩家坦克是player对象,再定义几个特别的装备,增加速度,增加生命,增加攻击力。对于这个场景,可以定制一下几个方法:

1
2
3
4
5

void addSpeed(Player player);
void addLife(Player player);
void addAttack(Player player);

这个方法定下来,就可以设计我们的程序,怎么设计呢? 我们可以设计一个最简单的设计,写一个静态的帮助类,代码实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
public class EquipmentHelper{
public void addSpeed(Player player){

}
public void addLife(Player player){

}
public void addAttack(Player player){

}

}

这个写完之后,我们们觉是可以实现我们的功能的?但是我们在条用的时候,是不是判断的逻辑比较多?如果类型比较多的时候,我们的系统就很难再维护了。

1
2
3
4
5
6
7
if(equipment is Speed){
equipmentHelper.addSpeed(player);
}
if(equipment is Life){
equipmentHelper.addLife(player);
}
....
阅读更多

设计模式--03.观察者模式

观察者模式

观察者模式是一个消息的派发的模式,是把被观察者的状态能够及时的通知给观察者。

比如一个超市的打折了,需要把消息通知给每一个超市的顾客,这样就可以把超市作为一个被观察者,而顾客是观察者。

实现逻辑

观察者模式实现的类图如下:

观察者模式

实现步骤:

  1. 定义一个Observer接口,约束观察者(顾客)需要实现的方法:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21

    public interface Observer {
    void reciveMessage(double price);
    }

    public class CusmtomerObserver1 implements Observer {
    @Override
    public void reciveMessage(double price) {

    System.out.println("CusmtomerObserver1 收到了价格消息:" + price);
    }
    }

    public class CusmtomerObserver2 implements Observer {
    @Override
    public void reciveMessage(double price) {

    System.out.println("CusmtomerObserver2 收到了价格消息:" + price);
    }
    }

  2. 实现被观察对象的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    public class MarketSubject {
    private double price;
    public double getPrice() {
    return price;
    }

    public void setPrice(double price) {
    this.price = price;
    notifyObserver(price);
    }

    private ArrayList<Observer> observerList=new ArrayList<>();
    public void addObserver(Observer observer){
    observerList.add(observer);
    }

    public void removeObserver(Observer observer){
    observerList.remove(observer);
    }

    public void notifyObserver(double price){
    for (Observer ob : observerList) {
    ob.reciveMessage(price);
    }
    }
    }

  3. 实现方法的注册和通知

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class ObserverMain {
    public static void main(String[] args) {
    MarketSubject marketSubject=new MarketSubject();
    marketSubject.addObserver(new CusmtomerObserver1());
    marketSubject.addObserver(new CusmtomerObserver2());
    marketSubject.setPrice(100d);

    }
    }

    运行结果:

1
2
CusmtomerObserver1 收到了价格消息:100.0
CusmtomerObserver2 收到了价格消息:100.0
阅读更多

设计模式--02.命令模式

命令模式

命令模式是把对象的操作方法分成一个命令,分别去执行。在分布式环境中,熔断和降级组件使用的设计模式就是命令模式。

为了了解什么是设计模式,可以类比下设计一个万能遥控器的设置,遥控器只负责一个方法的调用,真正的方法实现都在对应的电器上面。

使用的时候,只需要对对应的命令和实体进行注册下就可以了。具体的设计类图如下:

IO

具体实现代码分下面几个步骤:

  1. 定义实体方法的约束,也就是当前类实体有哪些方法,比如控制灯和电视,都有开和关的方法

    1
    2
    3
    4
    5
    6
    7
    public interface CommandObj {

    void on() ;

    void off();
    }

  2. 定义对应的类实体具体的实现方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class Light implements CommandObj {
    public void on(){
    System.out.println("打开电灯。。。");
    }

    public void off(){
    System.out.println("关闭电灯。。。");
    }
    }

    public class TV implements CommandObj{
    public void on(){
    System.out.println("打开电视。。。");
    }

    public void off(){
    System.out.println("关闭电视。。。");
    }

    }

  3. 定义一个命令执行的约束,来约束所有的Command的执行者需要实现的方法

    此处需要注意,在是实现了同一个CommandObj接口的实体,不需要Command的约束,为了Demo的完整性,把Commad接口加上。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    public interface Command {
    void execute();
    }

    public class WrapperOffCommand implements Command {
    CommandObj commandObj;

    public WrapperOffCommand(CommandObj commandObj){
    this.commandObj = commandObj;
    }

    @Override
    public void execute() {
    commandObj.off();
    }
    }

    public class WrapperOnCommand implements Command {
    CommandObj commandObj;

    public WrapperOnCommand(CommandObj commandObj){
    this.commandObj = commandObj;
    }

    @Override
    public void execute() {
    commandObj.on();
    }
    }

  4. 实现Controller的方法,即控制器本身

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    public class RemoteController {
    ConcurrentHashMap<String,Command> onCommands;
    ConcurrentHashMap<String,Command> offCommands;

    public RemoteController(){
    this.onCommands = new ConcurrentHashMap<>();
    this.offCommands = new ConcurrentHashMap<>();
    }

    public void registerCommand(String key, Command onCommand, Command offCommand){
    onCommands.put(key,onCommand);
    offCommands.put(key,offCommand);
    }

    // 按下开按钮
    public void onButtonPressed(String key){
    onCommands.get(key).execute();
    }

    // 按下关按钮
    public void offButtonPressed(String key){
    offCommands.get(key).execute();
    }
    }

  5. 控制器的使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
       public static void main(String[] args) {
    CommandObj light = new Light();
    CommandObj tv = new TV();

    Command lightOn = new WrapperOnCommand(light);
    Command lightOff = new WrapperOffCommand(light);
    Command TVOn = new WrapperOnCommand(tv);
    Command TVOff = new WrapperOffCommand(tv);


    RemoteController remoteController = new RemoteController();
    //注册对应的命令
    remoteController.registerCommand(RemoteTypeEnum.Light.toString(), lightOn, lightOff);
    //注册对应的命令
    remoteController.registerCommand(RemoteTypeEnum.TV.toString(), TVOn, TVOff);


    remoteController.onButtonPressed(RemoteTypeEnum.Light.toString());
    remoteController.offButtonPressed(RemoteTypeEnum.Light.toString());
    remoteController.onButtonPressed(RemoteTypeEnum.TV.toString());
    remoteController.offButtonPressed(RemoteTypeEnum.TV.toString());
    }

阅读更多

设计模式--01.单例模式

在程序设计中,需要保证一个只有一个对象实例,就是所谓的单例模式。在java中,有很多单例模式的实现,这篇博客是对这几种单例模式的优缺点进行分析和优化:

饿汉模式


所谓饿汗模式,就是优先创建对象,对象在类加载的时候就已经创建好了,具体的代码如下:

1
2
3
4
5
private static Singleton01 instance = new Singleton01();

public static Singleton01 getInstance() {
return instance;
}

饿汗模式优点是代码简单,由于是在类加载的时候就已经创建好了对象,所以不存在线程安全的问题。

缺点是:有的类在没有使用的时候就已经创建了对象,产生了多余的垃圾对象。


懒汉模式

阅读更多