对设计模式的总结,并用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工厂
单例模式
适用场景
当类只希望有一个实例的时候
编程实例
- 懒汉式
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;
}
- 饿汉式
可以对静态变量直接做初始化操作,但是这样失去了延迟初始化节约资源的优势。
private static Singleton sIntance = new Singleton();
- 内部类
可以在内部类中的静态变量做初始化操作,这样既线程安全,也可以延迟初始化
class Singleton {
static class InnerClass {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton() {
}
public static Singleton getsIntance() {
return InnerClass.INSTANCE;
}
}
- 枚举法(推荐)
简便有效,原理是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对象。
原型模式
通过拷贝原型来创建新的实例。
适应场景
- 对象类型需要在运行时确定。
- 对象之间的区别比较小,通过拷贝原型再修改的成本要小于直接创建对象。
编程实例
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");
}
结构型模式
适配器模式
适配器模式可以在适配器中包装一个不兼容的类,使其与另一个类兼容。
有两种实现方式:对象方式和类方式。对象方式是让适配器拥有一个待适配的对象,从而把相应的处理委托个这个对象。类方式则用到了多重继承,同时实现原有类和所需要的接口。
适用场景
- 希望使用现有的类,但是他的接口不是你想要的
- 使用适配器作为第三方库和程序的中间层
编程实例
我们购买了一个进口的电器,要求电压是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();
}
桥接模式
使抽象和实现分离,两者可以同时变化。 桥接模式把抽象与实现解耦,也就是把强关系(继承)转换为弱关系(关联关系,如组合)。
适用场景
- 希望在抽象角色与具体角色之间增加更多的灵活性,而不是直接的静态继承
- 一个类存在两个独立变化的维度,并且两个维度都需要扩展
编程实例
武器可以有不同种类,并且可以附带不同的魔法属性。传统方法可以为每个武器创建不同魔法的子类,也可以直接对武器设置魔法属性(组合的方法)
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();
}
组合模式
将对象组合成树结构来表现“整体/部分”层次结构,组合能让客户以一致的方式处理对象和组合对象
适用场景
- 想表示“整体/部分”层次结构
- 希望可以忽略单一对象与组合对象之间的差异,统一处理单一对象和组合对象
编程实例
每句话均有单词组成,每个单词由字母组成,这就是一个树型的结构。每个对象是可以打印的,并且有一些不同的打印规则,比如单词前有空格,句子后有句号。
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();
}
外观模式
为子系统的一组接口提供一个高级的,统一的接口
适用场景
- 希望为复杂的子系统提供简单的接口
- 希望使子系统分层,可以通过外观模式定义子系统的入口
编程实例
起床之后开灯,开电视,睡觉前关灯,关电视。不使用外观模式的话,就要单独的操作每个电器,可以使用外观模式统一的操作所有电器
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以内)里是共享内存的,直接用“==”是相等的
代理模式
给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用
代理模式与装饰模式很相似。但是代理模式关注的是对目标对象的控制,直接访问目标对象不方便或者不符合需要,往往是在代理类中或者远程创建对象。而装饰模式是希望动态地在对象上添加方法,往往是在装饰者外创建实例并通过参数传入装饰着。总结来说区别就是代理类和目标对象的关系在编译时就确定了,而装饰者可以在运行时递归的构造。
适用场景
- 访问控制:控制目标对象的访问权限
- 远程代理:为一个对象在不同的地址空间提供局部的代表时
编程实例
巫医会去当地的塔中学习魔法,但是只有前三个可以进入学习。
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,可以在运行时动态的调用代理实例的方法。
行为模式
职责链模式
使多个对象都有机会处理请求,从而避免请求的发起者和接受者之间的耦合关系。将这些对象连成一个链,并沿着这条链传递请求直到有对象处理它为止。
适用场景
- 不止一个对象可以处理请求,并且发起者不知道哪个会处理请求。比如点击事件的分发。
- 想向其中一个对象发送请求,又不想指定接收者
编程实例
兽王向军队发送命令,最先由指挥官接收命令,再下达到士兵,构成一条职责链
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"));
}
现实例子
- Logger类的log方法
- servlet.Filter的doFilter方法
命令模式
将命令封装为对象,以便使用不同的命令来参数化其他对象。
适用场景
- 抽象出待执行的动作以参数化某对象,这种机制类似于回调函数。先注册好动作,在适当的时候通过命令来执行
- 需要支持取消,重做操作
编程实例
巫师通过缩小魔法使哥布林变小
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命令
解释器模式
给定一个语言,为它的语言定义一种表示,解释器使用这个表示来解释语言中的句子
迭代器模式
提供顺序访问一个聚合对象中各个元素的方法,而又不暴露聚合对象内部的表示
适用场景
- 访问一个聚合对象的内容而无暴露它的内部表示
- 为遍历不同的聚合结构提供一个统一的接口
现实例子
实现Iterable接口的容器类
中介者模式
用中介者对象来封装一系列的对象交互。中介者使对象不需要显示的相互引用,从而使其松耦合
适用场景
- 一组对象定义良好,但是之间的相互依赖关系复杂
- 一个对象引用大量其他对象,并且直接与这些对象通信,导致难以复用
备忘录模式
在不破坏封装性的前提下,捕获一个对象的内部状态并备份,以便之后可以把这个对象恢复到之前的状态。
适用场景
- 必须保存一个对象在某一时刻的状态
- 获取状态的接口会暴露内部细节的时候
编程实例
记录下行走了多少距离与消耗的时间,获取备份没有暴露任何细节接口。
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();
}
观察者模式
描述了对象间的一对多关系,当一个对象发生改变时,所有依赖于它的对象都得到通知并被自动更新
适用场景
- 当一个抽象模型有两方面,其中一个依赖于另一个。将二者独立的封装,以便可以独自地改变和复用
- 当一个对象改变,需要有多个对象同时改变,而又不知道有多少对象待改变
编程实例
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();
}
状态模式
允许一个对象在其内部状态改变时改变它的行为
适用场景
- 一个对象的行为取决于它的当前状态
现实例子
React(一个js UI库)组件中的state
策略模式
定义一系列算法,把他们一个个封装起来,并且使它们可以相互替换。
适用场景
- 需要使用一个算法的不同变体
- 需要多相关类仅仅是行为有区别,“策略”提供了一种用多种行为中的一个行为配置一个类的方法
访问者模式
表示一个作用于某对象结构中的各元素的操作
适用场景
- 数据结构稳定,作用于数据结构的操作经常变化
模板方法模式
定义了一个操作中算法的骨架,而将一些步骤延迟到子类中
适用场景
- 一次性实现一个算法的不变部分,把可变的行为留个子类实现
- 子类中的公共行为应该被提取出来集中到一个公共父类中