设计模式学习笔记

对设计模式的总结,并用java进行实现。

创建型模式

工厂模式

适用场景

希望根据不同情况创建不同的子类,而不是直接创建具体的类。

简单工厂模式

这不是一个设计模式,更像是一种编程习惯。有一些子类实现了同一个接口,要根据需求实例化具体的实例,可以把实例化的操作放在工厂中,由工厂决定实例化哪个子类。

模式组成:抽象产品,具体产品,工厂

编程实例

铁匠可以制造武器,精灵需要精灵武器,兽人需要兽人武器,铁匠根据顾客制造具体的武器。

public interface Weapon {
    void attack();
}

enum CareerType {
    ELF,
    ORC
}

class ElfWeapon implements Weapon {
    @Override
    public void attack() {
        System.out.println("Elf attack.");
    }
}

class OrcWeapon implements Weapon {
    @Override
    public void attack() {
        System.out.println("Orc attack.");
    }
}
public class SimpleFactory {
    public Weapon manufactureWeapon(CareerType CareerType) {
        switch (CareerType) {
            case ELF:
                return new ElfWeapon();
            case ORC:
                return new OrcWeapon();
            default:
                throw new UnsupportedOperationException();
        }
    }
}
public static void main(String[] args) {
    SimpleFactory factory = new SimpleFactory();
    Weapon elfWeapon = factory.manufactureWeapon(CareerType.ELF);
    Weapon orcWeapon = factory.manufactureWeapon(CareerType.ORC);
    elfWeapon.attack();
    orcWeapon.attack();
}

工厂方法模式

简单工厂模式中,如果还需要再加新的武器,就需要在工厂中修改相应的分支,容易造成错误。 工厂方法是相当于对工厂做了一层抽象,核心工厂只提供工厂子类所需要的接口,实例化过程推迟到子类,这样添加新的武器就不需要修改原有的工厂角色。

模式组成:抽象产品,具体产品,抽象工厂,具体工厂

编程实例

还是用铁匠的例子。

public interface FactoryMethod {
    Weapon manufactureWeapon();
}

class ElfFactory implements FactoryMethod {

    @Override
    public Weapon manufactureWeapon() {
        return new ElfWeapon();
    }
}

class OrcFactory implements FactoryMethod {

    @Override
    public Weapon manufactureWeapon() {
        return new OrcWeapon();
    }
}
public static void main(String[] args) {
    FactoryMethod elfFactory = new ElfFactory();
    elfWeapon = elfFactory.manufactureWeapon();
    FactoryMethod orcFactory = new OrcFactory();
    orcWeapon = orcFactory.manufactureWeapon();
    elfWeapon.attack();
    orcWeapon.attack();
}
现实例子

java.util.Calendar包中的getIntance方法,可以根据时区返回相应的Calendar实例

public static Calendar getInstance(TimeZone zone)

抽象工厂模式

与工厂方法相比,抽象层次又多了一层,工厂方法的工厂子类依赖于某个具体的类,而抽象工厂的工厂子类是创建一组具有关联的实例,依赖于抽象。

模式组成:抽象产品族,抽象产品,具体产品,抽象工厂,具体工厂

编程实例

在之前的铁匠例子中,加入盔甲的制造。铁匠可以给精灵或兽人制造武器和盔甲。

interface EquipFactory {
    Weapon manufactureWeapon();
    Armor manufactureArmor();
}

class ElfAbstractFactory implements EquipFactory {

    @Override
    public Weapon manufactureWeapon() {
        return new ElfWeapon();
    }

    @Override
    public Armor manufactureArmor() {
        return new ElfArmor();
    }
}

class OrcAbstractFactory implements EquipFactory {

    @Override
    public Weapon manufactureWeapon() {
        return new OrcWeapon();
    }

    @Override
    public Armor manufactureArmor() {
        return new OrcArmor();
    }
}
public class AbstractFactory {
    static public EquipFactory makeFactory(CareerType careerType) {
        switch (careerType) {
            case ELF:
                return new ElfAbstractFactory();
            case ORC:
                return new OrcAbstractFactory();
            default:
                throw new UnsupportedOperationException();
        }
    }
}
public static void main(String[] args) {
    EquipFactory elfEquioFactory = AbstractFactory.makeFactory(CareerType.ELF);
    EquipFactory orcEquioFactory = AbstractFactory.makeFactory(CareerType.ORC);
    elfWeapon = elfEquioFactory.manufactureWeapon();
    Armor elfArmor = elfEquioFactory.manufactureArmor();
    orcWeapon = orcEquioFactory.manufactureWeapon();
    Armor orcArmor = orcEquioFactory.manufactureArmor();
    elfArmor.defense();
    orcArmor.defense();
    elfWeapon.attack();
    orcWeapon.attack();
}
现实例子

javax.xml.xpath.XPathFactory包可以通过uri返回一个Xpath工厂

单例模式

适用场景

当类只希望有一个实例的时候

编程实例

  1. 懒汉式
public class Singleton {
    private static Singleton sIntance;
    private Singleton() {

    }

    public Singleton getsIntance() {
        if (sIntance == null) {
            sIntance = new Singleton();
        }

        return sIntance;
    }
}

但是这是线程不安全的,可以通过对方法加锁,避免多个线程进入该方法。

public static Singleton getsIntance() {
    if (sIntance == null) {
        sIntance = new Singleton();
    }

    return sIntance;
}

但是这样会有性能上的问题,会出现线程等待的情况。可以使用双重校验锁的方法,只对初始化的时候做加锁操作。

public static Singleton getsIntance() {
    if (sIntance == null) {
        synchronized (Singleton.class) {
            if (sIntance == null) {
                sIntance = new Singleton();
            }
        }
    }

    return sIntance;
}
  1. 饿汉式

可以对静态变量直接做初始化操作,但是这样失去了延迟初始化节约资源的优势。

private static Singleton sIntance = new Singleton();
  1. 内部类

可以在内部类中的静态变量做初始化操作,这样既线程安全,也可以延迟初始化

class Singleton {
    static class InnerClass {
        private static final Singleton INSTANCE = new Singleton();
    }
    private Singleton() {

    }

    public static  Singleton getsIntance() {
        return InnerClass.INSTANCE;
    }
}
  1. 枚举法(推荐)

简便有效,原理是INTANCE会作为enum的static变量存在,可以直接访问INTANCE得到单例

public enum Singleton {
    INTANCE;
}

建造者模式

建造者模式将一个复杂的对象的创建和表示分开,使得相同的创建过程可以创建不同的表示。当构造函数参数很多时,往往要考虑建造者模式。

在建造者模式中会有个builder来管理对象参数,往往每个管理方法都会返回builder,这样就可以通过链式调用来清晰的表现创建对象的过程。

适用场景

一个对象的创建方法很复杂,有很复杂的内部结构。希望可以分离对象的创建和使用,并使得相同的创建过程可以创建不同的产品,或者是把创建过程分解为很多部分,简化创建过程。

编程实例

在游戏一开始创建角色的时候,你可以逐一的选择姓名,职业,初始武器装备等等,生成角色的过程变成了一个逐步的过程。

public class Hero {
    Weapon weapon;
    Armor armor;
    String name;
    String career;

    public Hero(Builder builder) {
        this.name = builder.name;
        this.career = builder.career;
        this.weapon = builder.weapon;
        this.armor = builder.armor;
    }
}

class Builder {
    Weapon weapon;
    Armor armor;
    String name;
    String career;

    public Builder(String name, String career) {
        this.name = name;
        this.career = career;
    }

    public Builder withWeapon(Weapon weapon) {
        this.weapon = weapon;
        return this;
    }

    public Builder withArmor(Armor armor) {
        this.armor = armor;
        return this;
    }

    public Hero build() {
        return new Hero(this);
    }
}
public static void main(String[] args) {
    Hero hero = new Builder("hero", "Orc").withWeapon(new OrcWeapon()).withArmor(new OrcArmor()).build();
    hero.weapon.attack();
    hero.armor.defense();
}

现实例子

Stringbuilder就使用了建造者模式,像append,insert等操作仍然返回Stringbuilder。而substring和toString就有点类似于build方法,创建一个实际的String对象。

原型模式

通过拷贝原型来创建新的实例。

适应场景

  1. 对象类型需要在运行时确定。
  2. 对象之间的区别比较小,通过拷贝原型再修改的成本要小于直接创建对象。

编程实例

java可以轻易的实现原型模式,只要实现Cloneable接口,并使用clone方法即可拷贝

public class Sheep implements Cloneable {
    String name;

    public Sheep(String name) {
        this.name = name;
    }

    public void setName(String name) { this.name = name; }
    public String getName() { return name; }

    @Override
    public Sheep clone() {
        return new Sheep(this.name);
    }
}
public static void main(String[] args) {
    Sheep jolly = new Sheep("Jolly");

    Sheep dolly = jolly.clone();
    dolly.setName("Dolly");
}

结构型模式

适配器模式

适配器模式可以在适配器中包装一个不兼容的类,使其与另一个类兼容。

有两种实现方式:对象方式和类方式。对象方式是让适配器拥有一个待适配的对象,从而把相应的处理委托个这个对象。类方式则用到了多重继承,同时实现原有类和所需要的接口。

适用场景

  1. 希望使用现有的类,但是他的接口不是你想要的
  2. 使用适配器作为第三方库和程序的中间层

编程实例

我们购买了一个进口的电器,要求电压是110V,但是国内的电压是220V,需要一个适配器把220V的电压转变成110V以兼容进口电器

interface Target_110V {
    void work_110V();
}

interface Target_220V {
    void work_220V();
}

class ImportTV implements Target_110V {

    @Override
    public void work_110V() {
        System.out.println("Work.");
    }
}

public class Adapter implements Target_220V {
    private ImportTV tv;

    public Adapter(ImportTV tv) {
        this.tv = tv;
    }

    @Override
    public void work_220V() {
        this.tv.work_110V();
    }
}
public static void main(String[] args) {
    ImportTV tv = new ImportTV();
    Adapter adapter = new Adapter(tv);
    adapter.work_220V();
}

桥接模式

使抽象和实现分离,两者可以同时变化。 桥接模式把抽象与实现解耦,也就是把强关系(继承)转换为弱关系(关联关系,如组合)。

适用场景

  1. 希望在抽象角色与具体角色之间增加更多的灵活性,而不是直接的静态继承
  2. 一个类存在两个独立变化的维度,并且两个维度都需要扩展

编程实例

武器可以有不同种类,并且可以附带不同的魔法属性。传统方法可以为每个武器创建不同魔法的子类,也可以直接对武器设置魔法属性(组合的方法)

public interface Magic {
    String magicApply();
}

class IceMagic implements Magic {

    @Override
    public String magicApply() {
        return "Ice";
    }
}

class FireMagic implements Magic {

    @Override
    public String magicApply() {
        return "Fire";
    }
}

public interface Weapon {
    void attack();
}

class Sword implements Weapon {
    private Magic magic;

    public Sword(Magic magic) {
        this.magic = magic;
    }

    @Override
    public void attack() {
        System.out.println(this.magic.magicApply() + " sword attack.");
    }
}

class Hammer implements Weapon {
    private Magic magic;

    public Hammer(Magic magic) {
        this.magic = magic;
    }

    @Override
    public void attack() {
        System.out.println(this.magic.magicApply() + " hammer attack.");
    }
}
public static void main(String[] args) {
    Weapon weapon = new Sword(new FireMagic());
    weapon.attack();
}

组合模式

将对象组合成树结构来表现“整体/部分”层次结构,组合能让客户以一致的方式处理对象和组合对象

适用场景

  1. 想表示“整体/部分”层次结构
  2. 希望可以忽略单一对象与组合对象之间的差异,统一处理单一对象和组合对象

编程实例

每句话均有单词组成,每个单词由字母组成,这就是一个树型的结构。每个对象是可以打印的,并且有一些不同的打印规则,比如单词前有空格,句子后有句号。

public abstract class LetterComposite {
    private List<LetterComposite> chidlren = new ArrayList<>();

    public void add(LetterComposite letterComposite) {
        this.chidlren.add(letterComposite);
    }

    public void printBefore() {}
    public void printAfter() {}

    public void print() {
        printBefore();
        for (LetterComposite l : this.chidlren) {
            l.print();
        }
        printAfter();
    }
}

class Letter extends LetterComposite {
    private char c;

    public Letter(char c) {
        this.c = c;
    }

    @Override
    public void printBefore() {
        System.out.print(this.c);
    }
}

class Word extends LetterComposite {
    public Word(List<Letter> letters) {
        for (Letter l : letters) {
            this.add(l);
        }
    }

    @Override
    public void printBefore() {
        System.out.print(" ");
    }
}

class Sentence extends LetterComposite {
    public Sentence(List<Word> words) {
        for (Word w : words) {
            this.add(w);
        }
    }

    @Override
    public void printAfter() {
        System.out.print(".");
    }
}
public static void main(String[] args) {
    List<Word> words = new ArrayList<>();

    words.add(new Word(Arrays.asList(new Letter('H'), new Letter('e'),new Letter('l'), new Letter('l'), new Letter('o'))));
    words.add(new Word(Arrays.asList(new Letter('w'), new Letter('o'),new Letter('r'), new Letter('l'), new Letter('d'))));
    Sentence sentence = new Sentence(words);
    sentence.print();
}

现实例子

各个UI库中组件。组件间有包含关系,但又继承自通过一个父类。

装饰模式

装饰模式可以动态给对象添加额外的职责,但是不影响其他同类的对象。在java中一般通过组合的方式在装饰类中持有所扩展的对象

适用场景

希望扩展功能,但是通过子类扩展功能不切实际时(比如类的定义被隐藏)

编程实例

兽人有的时候空手,有的时候可使用棍棒

interface Orc {
    void attack();
    int getPower();
}

class SimpleOrc implements Orc {

    @Override
    public void attack() {
        System.out.println("Punch.");
        System.out.println("Power is " + getPower());
    }

    @Override
    public int getPower() {
        return 10;
    }
}
public class Decorator implements Orc{
    private SimpleOrc orc;

    public Decorator(SimpleOrc orc) {
        this.orc = orc;
    }

    @Override
    public void attack() {
        System.out.println("Swing with a club.");
        System.out.println("Power is " + getPower());
    }

    @Override
    public int getPower() {
        return orc.getPower() + 10;
    }
}
public static void main(String[] args) {
    SimpleOrc simpleOrc = new SimpleOrc();
    simpleOrc.attack();

    Decorator orc = new Decorator(simpleOrc);
    orc.attack();
}

外观模式

为子系统的一组接口提供一个高级的,统一的接口

适用场景

  1. 希望为复杂的子系统提供简单的接口
  2. 希望使子系统分层,可以通过外观模式定义子系统的入口

编程实例

起床之后开灯,开电视,睡觉前关灯,关电视。不使用外观模式的话,就要单独的操作每个电器,可以使用外观模式统一的操作所有电器

class Light {
    public void on() {
        System.out.println("Turn on the light.");
    }

    public void off() {
        System.out.println("Turn off the light.");
    }
}

class Television {
    public void on() {
        System.out.println("Turn on the television.");
    }

    public void off() {
        System.out.println("Turn off the television.");
    }
}
public class Facade {
    private Light light;
    private Television television;

    public Facade() {
        light = new Light();
        television = new Television();
    }

    public void on() {
        light.on();
        television.on();
    }

    public void off() {
        light.off();
        television.off();
    }
}
public static void main(String[] args) {
    Facade facade = new Facade();
    facade.on();
    facade.off();
}

享元模式

通过使相似的对象共享内存来减少内存开销

编程实例

巫医商店中有魔法药水,相同种类的药水功效是相同的,没必要再新建对象。

interface Potion {
    void drink();
}

class HealingPotion implements Potion {

    @Override
    public void drink() {
        System.out.printf("Healed.This is %d\n", System.identityHashCode(this));
    }
}

class HolyWaterPotionPotion implements Potion {

    @Override
    public void drink() {
        System.out.printf("Blessed.This is %d\n", System.identityHashCode(this));
    }
}

enum PotionType {
    HEALING,
    HOLY_WATER
}
public class PotionFactory {
    private final Map<PotionType, Potion> potions;

    public PotionFactory() {
        potions = new EnumMap<PotionType, Potion>(PotionType.class);
    }

    public Potion createPotion(PotionType type) {
        Potion potion = potions.get(type);

        if (potion == null) {
            switch (type) {
                case HEALING:
                    potion = new HealingPotion();
                    potions.put(type, potion);
                    break;
                case HOLY_WATER:
                    potion = new HolyWaterPotionPotion();
                    potions.put(type, potion);
                    break;
            }
        }

        return potion;
    }
}
public static void main(String[] args) {
    PotionFactory potions = new PotionFactory();
    potions.createPotion(PotionType.HEALING).drink();
    potions.createPotion(PotionType.HEALING).drink();
    potions.createPotion(PotionType.HOLY_WATER).drink();
    potions.createPotion(PotionType.HOLY_WATER).drink();
}

现实例子

包装类Integer中,在较小的范围(128以内)里是共享内存的,直接用“==”是相等的

代理模式

给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用

代理模式与装饰模式很相似。但是代理模式关注的是对目标对象的控制,直接访问目标对象不方便或者不符合需要,往往是在代理类中或者远程创建对象。而装饰模式是希望动态地在对象上添加方法,往往是在装饰者外创建实例并通过参数传入装饰着。总结来说区别就是代理类和目标对象的关系在编译时就确定了,而装饰者可以在运行时递归的构造。

适用场景

  1. 访问控制:控制目标对象的访问权限
  2. 远程代理:为一个对象在不同的地址空间提供局部的代表时

编程实例

巫医会去当地的塔中学习魔法,但是只有前三个可以进入学习。

class Wizard {
    public String name;

    public Wizard(String name) {
        this.name = name;
    }
}

interface TowerInterface {
    void enter(Wizard wizard);
}

class Tower implements TowerInterface {
    @Override
    public void enter(Wizard wizard) {
        System.out.println(wizard.name + " enters the tower.");
    }

}
public class TowerProxy implements TowerInterface {
    private final static int NUM_Wizard_ALLOWED = 3;
    private int numWizards = 0;

    private Tower tower;

    public TowerProxy() {
        tower = new Tower();
    }

    @Override
    public void enter(Wizard wizard) {
        if (numWizards < NUM_Wizard_ALLOWED) {
            tower.enter(wizard);
            numWizards++;
        } else {
            System.out.println(wizard.name + " is not allowed to enter the tower.");
        }
    }
}
public static void main(String[] args) {
    TowerProxy towerProxy = new TowerProxy();
    towerProxy.enter(new Wizard("Red"));
    towerProxy.enter(new Wizard("Blue"));
    towerProxy.enter(new Wizard("Green"));
    towerProxy.enter(new Wizard("Black"));
}

现实例子

java的动态代理类Proxy,可以在运行时动态的调用代理实例的方法。

行为模式

职责链模式

使多个对象都有机会处理请求,从而避免请求的发起者和接受者之间的耦合关系。将这些对象连成一个链,并沿着这条链传递请求直到有对象处理它为止。

适用场景

  1. 不止一个对象可以处理请求,并且发起者不知道哪个会处理请求。比如点击事件的分发。
  2. 想向其中一个对象发送请求,又不想指定接收者

编程实例

兽王向军队发送命令,最先由指挥官接收命令,再下达到士兵,构成一条职责链

enum RequestType {
    DEFEND_CASTLE,
    COLLECT_TAX
}

class Request {
    private final RequestType type;
    private final String requestDescription;
    private boolean handled;

    public Request(final RequestType type, final String requestDescription) {
        this.type = type;
        this.requestDescription = requestDescription;
        handled = false;
    }

    public String getRequestDescription() {
        return requestDescription;
    }

    public RequestType getType() {
        return type;
    }

    public void markHandled() {
        this.handled = true;
    }

    public boolean isHandled() {
        return this.handled;
    }

    @Override
    public String toString() {
        return getRequestDescription();
    }
}

abstract class RequestHandler {
    private RequestHandler next;

    public RequestHandler(RequestHandler next) {
        this.next = next;
    }

    public void handleRequest(Request request) {
        if (next != null) {
            next.handleRequest(request);
        }
    }

    public void printHandleRequest(Request request) {
        System.out.println(this + " handling request " + request);
    }

    @Override
    public abstract String toString();
}

class CommanderHandler extends RequestHandler {

    public CommanderHandler(RequestHandler next) {
        super(next);
    }

    @Override
    public void handleRequest(Request request) {
        if (request.getType() == RequestType.DEFEND_CASTLE) {
            request.markHandled();
            printHandleRequest(request);
        } else {
            super.handleRequest(request);
        }
    }

    @Override
    public String toString() {
        return "Commander";
    }
}

class SoldierHandler extends RequestHandler {

    public SoldierHandler(RequestHandler next) {
        super(next);
    }

    @Override
    public void handleRequest(Request request) {
        if (request.getType() == RequestType.COLLECT_TAX) {
            request.markHandled();
            printHandleRequest(request);
        } else {
            super.handleRequest(request);
        }
    }

    @Override
    public String toString() {
        return "Soldier";
    }
}

public class OrcKing {
    private RequestHandler chain;

    public OrcKing() {
        buildChain();
    }

    private void buildChain() {
        chain = new CommanderHandler(new SoldierHandler(null));
    }

    public void makeReqeust(Request request) {
        chain.handleRequest(request);
    }
}
public static void main(String[] args) {
    OrcKing orcKing = new OrcKing();
    orcKing.makeReqeust(new Request(RequestType.DEFEND_CASTLE, "defend castle"));
    orcKing.makeReqeust(new Request(RequestType.COLLECT_TAX, "collect tax"));
}

现实例子

  1. Logger类的log方法
  2. servlet.Filter的doFilter方法

命令模式

将命令封装为对象,以便使用不同的命令来参数化其他对象。

适用场景

  1. 抽象出待执行的动作以参数化某对象,这种机制类似于回调函数。先注册好动作,在适当的时候通过命令来执行
  2. 需要支持取消,重做操作

编程实例

巫师通过缩小魔法使哥布林变小

public interface Command {
    void execute(Target target);
}

enum Size {
    SMALL,
    NORMAL
}

interface Target {
    Size getSize();
    void setSize(Size size);
    void printStats();
}

class ShrinkSpell implements Command {

    @Override
    public void execute(Target target) {
        target.setSize(Size.SMALL);
    }
}

class Goblin implements Target {
    private Size size;

    public Goblin() {
        this.size = Size.NORMAL;
    }

    @Override
    public Size getSize() {
        return size;
    }

    @Override
    public void setSize(Size size) {
        this.size = size;
    }

    @Override
    public String toString() {
        return "Goblin";
    }

    @Override
    public void printStats() {
        System.out.println(this + " is " + getSize());
    }
}

class Wizard {
    public void castSpell(Command command, Target target) {
        command.execute(target);
    }
}
public static void main(String[] args) {
    Goblin goblin = new Goblin();
    Wizard wizard = new Wizard();

    goblin.printStats();
    wizard.castSpell(new ShrinkSpell(), goblin);
    goblin.printStats();
}

现实例子

Runnable接口,run命令

解释器模式

给定一个语言,为它的语言定义一种表示,解释器使用这个表示来解释语言中的句子

迭代器模式

提供顺序访问一个聚合对象中各个元素的方法,而又不暴露聚合对象内部的表示

适用场景

  1. 访问一个聚合对象的内容而无暴露它的内部表示
  2. 为遍历不同的聚合结构提供一个统一的接口

现实例子

实现Iterable接口的容器类

中介者模式

用中介者对象来封装一系列的对象交互。中介者使对象不需要显示的相互引用,从而使其松耦合

适用场景

  1. 一组对象定义良好,但是之间的相互依赖关系复杂
  2. 一个对象引用大量其他对象,并且直接与这些对象通信,导致难以复用

备忘录模式

在不破坏封装性的前提下,捕获一个对象的内部状态并备份,以便之后可以把这个对象恢复到之前的状态。

适用场景

  1. 必须保存一个对象在某一时刻的状态
  2. 获取状态的接口会暴露内部细节的时候

编程实例

记录下行走了多少距离与消耗的时间,获取备份没有暴露任何细节接口。

interface WalkMemento {
}

public class Walk {
    private int time;
    private int distance;
    private Random random;

    public Walk() {
        time = 0;
        distance = 0;
        random = new Random();
    }

    public void timePassed() {
        time += random.nextInt(10);
        distance += random.nextInt(20);
    }

    public WalkMemento getMemento() {
        InternalMemento memento = new InternalMemento(time, distance);

        return memento;
    }

    public void setMemento(WalkMemento memento) {
        InternalMemento internalMemento = (InternalMemento)memento;
        this.time = internalMemento.getTime();
        this.distance = internalMemento.getDistance();
    }

    public void printStats() {
        System.out.printf("Spend %d s walking %d meters.\n", time, distance);
    }

    class InternalMemento implements WalkMemento {
        private int time;
        private int distance;

        public InternalMemento(int time, int distance) {
            this.time = time;
            this.distance = distance;
        }

        public int getTime() {
            return time;
        }

        public int getDistance() {
            return distance;
        }
    }
}
public static void main(String[] args) {
    Walk walk = new Walk();

    walk.printStats();
    walk.timePassed();
    walk.printStats();

    WalkMemento memento = walk.getMemento();

    walk.timePassed();
    walk.printStats();

    walk.setMemento(memento);
    walk.printStats();
}

观察者模式

描述了对象间的一对多关系,当一个对象发生改变时,所有依赖于它的对象都得到通知并被自动更新

适用场景

  1. 当一个抽象模型有两方面,其中一个依赖于另一个。将二者独立的封装,以便可以独自地改变和复用
  2. 当一个对象改变,需要有多个对象同时改变,而又不知道有多少对象待改变

编程实例

public class Weather {
    private List<WeatherObserver> observers;
    private WeatherType currentWeather;

    public Weather() {
        observers = new ArrayList<>();
    }

    public void addObserver(WeatherObserver observer) {
        observers.add(observer);
        currentWeather = WeatherType.RAINY;
    }

    public void removeObserver(WeatherObserver observer) {
        observers.remove(observer);
    }

    public void changeWeather() {
        WeatherType[] enumValues = WeatherType.values();
        currentWeather = enumValues[(currentWeather.ordinal() + 1) % enumValues.length];
        notifyObservers();
    }

    public void notifyObservers() {
        for (WeatherObserver observer : observers) {
            observer.update(currentWeather);
        }
    }
}

enum WeatherType {
    SUNNY,
    RAINY
}

interface WeatherObserver {
    void update(WeatherType type);
}

class Orc implements WeatherObserver {

    @Override
    public void update(WeatherType type) {
        switch (type) {
            case RAINY:
                System.out.println("Orc in the rain.");
                break;
            case SUNNY:
                System.out.println("Orc under the sun.");
                break;
        }
    }
}

class Wizard implements WeatherObserver {

    @Override
    public void update(WeatherType type) {
        switch (type) {
            case RAINY:
                System.out.println("Wizard in the rain.");
                break;
            case SUNNY:
                System.out.println("Wizard under the sun.");
                break;
        }
    }
}
public static void main(String[] args) {
    Weather weather = new Weather();
    Orc orc = new Orc();
    Wizard wizard = new Wizard();

    weather.addObserver(orc);
    weather.addObserver(wizard);
    weather.changeWeather();
    weather.removeObserver(wizard);
    weather.changeWeather();
}

状态模式

允许一个对象在其内部状态改变时改变它的行为

适用场景

  1. 一个对象的行为取决于它的当前状态

现实例子

React(一个js UI库)组件中的state

策略模式

定义一系列算法,把他们一个个封装起来,并且使它们可以相互替换。

适用场景

  1. 需要使用一个算法的不同变体
  2. 需要多相关类仅仅是行为有区别,“策略”提供了一种用多种行为中的一个行为配置一个类的方法

访问者模式

表示一个作用于某对象结构中的各元素的操作

适用场景

  1. 数据结构稳定,作用于数据结构的操作经常变化

模板方法模式

定义了一个操作中算法的骨架,而将一些步骤延迟到子类中

适用场景

  1. 一次性实现一个算法的不变部分,把可变的行为留个子类实现
  2. 子类中的公共行为应该被提取出来集中到一个公共父类中

odroid搭建Android实验环境过程

Published on September 18, 2018

Java并发编程知识总结

Published on August 26, 2018