Java23种设计模式总结(纯手打当作学习)

1. 总述

以下资料来自于疯狂联盟版的Java设计模式。因为网上扫描PDF一些字变成*号,并且个人想学习设计模式,所以下面是根据pdf和本人知识量来手打的内容,如果错误请包含。希望自己学完有所收获。

下面23种设计模式我都敲完代码也能运行了,放出百度网盘下载源码:链接: https://pan.baidu.com/s/1sYkTQrWk_SSLCGNzruwefQ 提取码: zgap

设计模式有两种分类方法,一种根据模式的目的来分;另一种根据模式的作用来分。

1.1 根据模式的目的划分

根据模式是用来完成什么样的工作来划分,这种方法可分为创建型模式、结构型模式、行为型模式3种。

1.1.1 创建型模式

用于描述“怎么创建对象”。它的主要特点是“将对象的创建与使用分离”。如,单例、原型、工厂方法、抽象工厂、建造者等5种创建型模式。

1.1.2 结构型模式

用于描述“如何将类或对象按某种布局组成更大的结构”。如,代理、适配器、桥接、装饰、外观、享元、组合等7种结构型模式。

1.1.3 行为型模式

用于描述“类或对象之间怎样相互协作共同完成单个对象无法单独完成的任务,以及怎样分配职责”。如,模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录模式、解释器等11中行为模式。

1.2 根据模式的作用划分

根据模式的主要用于类上还是主要用户对象上来分,这种方式可分为类模式和对象模式两种。

1.2.1 类模式

用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时便确定下来了。如,工厂方法、(类)适配器、模板方法、解释器等4种类模式。

1.2.2 对象模式

用户处理对象之间关系的,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。

 

2. 参考例子

 
创建型模式
  • AbstractFactory ( 抽象工厂 )
  • FactoryMethod ( 工厂方法 )
  • Singleton ( 单例模式 )
  • Builder ( 建造者模式 )
  • Prototype ( 原型模式 )
 
 

2.1 工厂方法

定义一个用于创建对象的接口,让子类决定实例化哪一个类。FactoryMethod使一个类的实例化延迟到其子类。

适用性

  1. 当一个类不知道它所必须创建的对象的类的时候。
  2. 当一个类希望由它的子类来指定它所创建的对象的时候。
  3. 当它将创建对象的职责委托给多个帮助子类中的某一个,并且希望将哪一个帮助子类是代理者这一信息局部化的时候。

参与者

  1. Product:定义工厂方法所创建的对象的接口
  2. ConcreteProduct:实现Product接口
  3. Creator:声明工厂方法,该方法返回一个Product类型的对象。Creator也可以定义一个工厂方法的缺省实现,它返回一个缺省的ConcreteProduct对象。可以调用工厂方法以创建一个Product对象。
  4. ConcreteCreator:重定义工厂方法以返回一个ConcreteProduct实例。

例子

//Product
public interface Work {
  void doWork();
}
//ConcreteProduct
public class StudentWork implements Work{

  @Override
  public void doWork() {
    System.out.println("学生做作业!");
  }
}
//ConcreteProduct
public class TeacherWork implements Work{

  @Override
  public void doWork() {
    System.out.println("老师审批作业!");
  }
}
//Creator
public interface IWorkFactory {
  Work getWork();
}
//ConcreteCreator
public class StudentWorkFactory implements IWorkFactory{

  @Override
  public Work getWork() {
    return new StudentWork();
  }
}
//ConcreteCreator
public class TeacherWorkFactory implements IWorkFactory{

  @Override
  public Work getWork() {
    return new TeacherWork();
  }
}
//启动
public class Test {

  public static void main(String[] args) {
    StudentWorkFactory studentWorkFactory = new StudentWorkFactory();
    studentWorkFactory.getWork().doWork();//学生做作业!

    TeacherWorkFactory teacherWorkFactory = new TeacherWorkFactory();
    teacherWorkFactory.getWork().doWork();//老师审批作业!
  }
}

 

2.2 抽象工厂

 

提供一个创建一系列相关或相互依赖对象的接口,而无需指定它们具体的类。

适用性

  1. 一个系统要独立于它的产品的创建、组合和表示时。
  2. 一个系统要由多个产品系列中的一个来配置时。
  3. 当你要强调一系列相关的产品对象的设计以便进行联合使用时。
  4. 当你提供一个产品的类库,而只是想显示它们的接口而不是实现时。
参与者
 
  1. AbstractFactory:声明一个创建抽象产品对象的操作接口。
  2. ConcreteFactory:实现创建具体产品对象的操作。
  3. AbstractProduct:为一类产品对象声明一个接口。
  4. ConcreteProduct:定义一个将被相应的具体工厂创建的产品对象。实现AbstractProduct接口。
  5. Client:仅使用由AbstractFactory和AbstractProduct类声明的接口。

例子

//abstractFactory
public interface IAnimalFactory {
  ICat createCat();
  IDog createDog();
}
//ConcreteFactory
public class BlackAnimalFactory implements IAnimalFactory {

  @Override
  public ICat createCat() {
    return new BlackCat();
  }

  @Override
  public IDog createDog() {
    return new BlackDog();
  }
}
//ConcreteFactory
public class WhiteAnimalFactory implements IAnimalFactory {

  @Override
  public ICat createCat() {
    return new WhiteCat();
  }

  @Override
  public IDog createDog() {
    return new WhiteDog();
  }
}
//AbstractProduct
public interface ICat {
  void eat();
}
//AbstractProduct
public interface IDog {
  void eat();
}
//ConcreteProduct
public class BlackCat implements ICat{

  @Override
  public void eat() {
    System.out.println("The black cat is eating!");
  }
}
//ConcreteProduct
public class WhiteCat implements ICat{

  @Override
  public void eat() {
    System.out.println("The white cat is eating!");
  }
}
//ConcreteProduct
public class BlackDog implements IDog{

  @Override
  public void eat() {
    System.out.println("The black dog is eating!");
  }
}
//ConcreteProduct
public class WhiteDog implements IDog{

  @Override
  public void eat() {
    System.out.println("The white dog is eating!");
  }
}
//启动
public class Client {
  public static void main(String[] args) {
    IAnimalFactory blackAnimalFactory = new BlackAnimalFactory();
    ICat blackCat = blackAnimalFactory.createCat();
    blackCat.eat();//The black cat is eating!

    IDog blackDog = blackAnimalFactory.createDog();
    blackDog.eat();//The black dog is eating!

    IAnimalFactory whiteAnimalFactory = new WhiteAnimalFactory();
    ICat whiteCat = whiteAnimalFactory.createCat();
    whiteCat.eat();//The white cat is eating!

    IDog whiteDog = whiteAnimalFactory.createDog();
    whiteDog.eat();//The white dog is eating!
  }
}

 

2.3 建造者模式

 

将一个复杂对象的构造与它的表示分离,使的同样的构造过程可以创建不同的表示。

适用性

  1. 当创建复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时。
  2. 当构造过程必须允许被构造的对象有不同的表示时。
参与者
 
  1. Builder:为创建一个Product对象的各个部件指定抽象接口。
  2. ConcreteBuilder:实现Builder的接口以构造和装配该产品的各个部件。定义并明确它所创建的表示。提供一个检索产品的接口。
  3. Director:为构造一个使用Builder接口的对象。
  4. Product:表示被构造的复杂对象。ConcreteBuilder创建该产品的内部表示并定义它的装配过程。包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

例子

//Product
public class Person {
  private String head;
  private String body;
  private String foot;

  //这里为了幅度,不展示getset方法。请自行为三个字段添加
}
//Product
public class Man extends Person{

}
//Builder
public interface PersonBuilder {

  void buildHead();
  void buildBody();
  void buildFoot();
  Person buildPerson();
}
//ConcreteBuilder
public class ManBuilder implements PersonBuilder{

  Person person;

  public ManBuilder() { person = new Man(); }

  @Override
  public void buildHead() {
    person.setHead("建造男人头部");
  }

  @Override
  public void buildBody() {
    person.setBody("建造男人身体");
  }

  @Override
  public void buildFoot() {
    person.setFoot("建造男人脚");
  }

  @Override
  public Person buildPerson() {
    return person;
  }
}
//Director
public class PersonDirector {
  public Person constructPerson(PersonBuilder pb) {
    pb.buildHead();
    pb.buildBody();
    pb.buildFoot();
    return pb.buildPerson(); }
}
//启动
public class Test {

  public static void main(String[] args) {
    PersonDirector pd = new PersonDirector();
    Person person = pd.constructPerson(new ManBuilder());
    System.out.println(person.getBody());//建造男人身体
    System.out.println(person.getFoot());//建造男人脚
    System.out.println(person.getHead());//建造男人头部
  }
}

2.4 单例模式

 

以前叫单态模式,学的最多的就是这个了。懒汉式,饿汉式,双重检查锁,静态生成,枚举生成。

保证一个类仅有一个实例,并提供一个访问它的全局访问点。

适用性

  1. 当类只能有一个实例并且客户可以从一个众所周知的访问点控制它时。
  2. 当这个唯一实例应该是通过子类化可扩展的,并且客户应该无需更改代码就能使用一个扩展的实例时。
参与者
 
  1. Singleton:定义一个 Instance 操作,允许客户访问它的唯一实例。Instance 是一个类操作。可能负责创建它自己的唯一实例。

例子

//Singleton
public class Singleton {
  private static Singleton singleton;

  public Singleton() {
  }

  public static Singleton getInstance() {
    if (singleton == null) {
      singleton = new Singleton();
    }
    return singleton;
  }
}
//启动
public class Test {
  public static void main(String[] args) {
    Singleton singleton = Singleton.getInstance();
    Singleton singleton1 = Singleton.getInstance();
    System.out.println(singleton);//four.Singleton@27f674d
    System.out.println(singleton1);//four.Singleton@27f674d
  }
}

2.5 原型模式

 

用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。

适用性

  1. 当一个系统应该独立于它的产品创建、构成和表示时。
  2. 当要实例化的类是在运行时刻指定时,例如,通过动态装载。
  3. 为了避免创建一个与产品类层次平行的工厂类层次时。
  4. 当一个类的实例只能有几个不同状态组合中的一种时。
  5. 建立相应数目的原型并克隆它们可能比每次用合适的状态手工实例化该类更方便一些。
参与者
 
  1. Prototype声明一个克隆自身的接口
  2. ConcretePrototype:实现一个克隆自身的操作。
  3. Client:让一个原型克隆自身从而创建一个新的对象。

例子

//Prototype
public class Prototype implements Cloneable {

  private String name;
  public void setName(String name) {
    this.name = name;
  }
  public String getName() {
    return this.name;
  }
  @Override
  public Object clone() {
    try {
      return super.clone();
    } catch (Exception e) {
      e.printStackTrace();
      return null;
    }
  }
}
//ConcretePrototype
public class ConcretePrototype extends Prototype{
  public ConcretePrototype(String name) {
    setName(name); }
}
//Client
//启动
public class Test {
  public static void main(String[] args) {
    Prototype pro = new ConcretePrototype("prototype");
    Prototype pro2 = (Prototype) pro.clone();
    System.out.println(pro.getName());//prototype
    System.out.println(pro2.getName());//prototype
  }
}
 

 

结构型模式

  • Adapter ( 适配器模式 )
  • Bridge ( 桥接模式 )
  • Composite ( 组合模式 )
  • Decorator ( 装饰模式 )
  • Facade ( 外观模式 )
  • Flyweight ( 享元模式 )
  • Proxy ( 代理模式 )

 

2.6 适配器模式

 

将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。

适用性

  1. 你想使用一个已经存在的类,而它的接口不符合你的需求。
  2. 你想创建一个可以复用的类,该类可以与其他不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作。
  3. (仅适用于对象Adapter)你想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口。
参与者
 
  1. Target:定义Client使用的与特定领域相关的接口。
  2. Client:与符合Target接口的对象协同。
  3. Adaptee:定义一个已经存在的接口,这个接口需要适配。
  4. Adapter:对Adaptee的接口与Target接口进行适配

例子

//Target
public interface Target {
  void adapteeMethod();
  void adapterMethod();
}
//Adaptee
public class Adaptee {
  public void adapteeMethod() {
    System.out.println("Adaptee method!");
  }
}
//Adapter
public class Adapter implements Target {

  private Adaptee adaptee;

  public Adapter(Adaptee adaptee) {
    this.adaptee = adaptee;
  }

  @Override
  public void adapteeMethod() {
    adaptee.adapteeMethod();
  }

  @Override
  public void adapterMethod() {
    System.out.println("Adapter method!");
  }
}
//Client
public class Test {
  public static void main(String[] args) {
    Target target = new Adapter(new Adaptee());
    target.adapteeMethod();//Adaptee method!

    target.adapterMethod();//Adapter method!
  }
}

 

2.7 桥接模式

 

将抽象部分与它的实现部分分离,使它们都可以独立地变化。

适用性

  1. 你不希望在抽象和它的实现部分之间有一个固定的绑定关系。例如这种情况可能是因为,在程序运行时刻实现部分应可以被选择或者切换。
  2. 类的抽象以及它的实现都应该可以通过生成子类的方法加以扩充。这时Bridge模式使你可以对不同的抽象接口和实现部分进行组合,并分别对它们进行扩充。
  3. 对一个抽象的实现部分的修改应对客户不产生影响,即客户的代码不必重新编译。
  4. 正如在意图一节的第一个类图中所示的那样,有许多类要生成。这样一种类层次结构说明你必须将一个对象分解成两个部分。
  5. 你想在多个对象间共享实现(可能使用引用计数),但同时要求客户并知道这一点。
参与者
 
  1. Abstraction:定义抽象类的接口。维护一个指向Implementor类型对象的指针。
  2. RefinedAbstraction:扩充由Abstraction定义的接口。
  3. Implementor:定义实现类的接口,该接口不一定要与Abstraction的接口完全一致。事实上这两个接口可以完全不同。一般来讲,Implementor接口仅提供基本操作,而Abstraction则定义了基于这些基本操作的较高层次的操作。
  4. ConcreteImpllementor:实现Implementor接口并定义它的具体实现。

例子

//Abstraction
public abstract class Person {
  private Clothing clothing;
  private String type;

  public abstract void dress();

  public Clothing getClothing() {
    return clothing;
  }

  public void setClothing(Clothing clothing) {
    this.clothing = clothing;
  }

  public String getType() {
    return type;
  }

  public void setType(String type) {
    this.type = type;
  }
}
//Implementor
public abstract class Clothing {
  public abstract void personDressCloth(Person person);
}
//RefinedAbstraction
public class Man extends Person{

  public Man() {
    setType("男人");
  }

  @Override
  public void dress() {
    Clothing clothing = getClothing();
    clothing.personDressCloth(this);
  }
}
//RefinedAbstraction
public class Lady extends Person{

  public Lady() {
    setType("女人");
  }

  @Override
  public void dress() {
    Clothing clothing = getClothing();
    clothing.personDressCloth(this);
  }
}
//ConcreteImplementor
public class Jacket extends Clothing {

  @Override
  public void personDressCloth(Person person) {
    System.out.println(person.getType() + "穿夹克");
  }
}
//ConcreteImplementor
public class Trouser extends Clothing {

  @Override
  public void personDressCloth(Person person) {
    System.out.println(person.getType() + "穿裤子");
  }
}
//启动
public class Test {
  public static void main(String[] args) {
    Person man = new Man();
    Person lady = new Lady();

    Clothing jacket = new Jacket();
    Clothing trouser = new Trouser();
    jacket.personDressCloth(man);//男人穿夹克
    trouser.personDressCloth(man);//男人穿裤子
    jacket.personDressCloth(lady);//女人穿夹克
    trouser.personDressCloth(lady);//女人穿裤子
  }
}

 

2.8 组合模式

 

将对象组合成树形结构以表示“部分-整体”的层次结构。“Composite使得用户对单个对象和组合对象的使用具有一致性。”

适用性

  1. 你想表示对象-整体的层次结构。
  2. 你希望用户忽略组合对象与单个对象的不同,用户统一地使用组合结构中的所有对象。
参与者
 
  1. Component:为组合中的对象声明接口。在适当的情况下,实现所有类共有接口的缺省行为。声明一个接口用户访问和管理Component的子组件。(可选)在递归结构中定义一个接口,用于访问一个父部件,并在合适的情况下实现它。
  2. Leaf:在组合中表示叶节点对象,叶节点没有子节点。在组合中定义节点对象的行为。
  3. Composite:定义有子部件的那些部件的行为。
  4. Client:通过Component接口操纵组合部件的对象。

例子

//Component
public abstract class Employer {
  private String name;

  public abstract void add(Employer employer);
  public abstract void delete(Employer employer);
  public List<Employer> employers;

  public String getName() {
    return name;
  }

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

  public void printInfo() {
    System.out.println(name);
  }
  public List<Employer> getEmployers() {
    return this.employers;
  }
}
//Leaf
public class Programmer extends Employer{

  public Programmer(String name) {
    setName(name);
    employers = null;//程序员, 表示没有下属了
  }

  @Override
  public void add(Employer employer) {

  }

  @Override
  public void delete(Employer employer) {

  }
}
//Leaf
public class ProjectAssistant extends Employer{
  public ProjectAssistant(String name) {
    setName(name);
    employers = null;//项目助理, 表示没有下属了
  }

  @Override
  public void add(Employer employer) {

  }

  @Override
  public void delete(Employer employer) {

  }
}
//Composite
public class ProjectManager extends Employer{

  public ProjectManager(String name) {
    setName(name);
    employers = new ArrayList();
  }

  @Override
  public void add(Employer employer) {
    employers.add(employer);
  }

  @Override
  public void delete(Employer employer) {
    employers.remove(employer);
  }
}
//Client
public class Test {
  public static void main(String[] args) {
    Employer pm = new ProjectManager("项目经理");
    Employer pa = new ProjectAssistant("项目助理");
    Employer programmer1 = new Programmer("程序员一");
    Employer programmer2 = new Programmer("程序员二");
    pm.add(pa);//为项目经理添加项目助理
    pm.add(programmer2);//为项目经理添加程序员
    List<Employer> ems = pm.getEmployers();
    for (Employer em : ems) {
      System.out.println(em.getName());//项目助理//程序员二
    }
  }
}

 

2.9 装饰模式

 

动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式相比生成子类更加灵活。

适用性

  1. 在不影响其它对象的情况下,以动态、透明的方式给单个对象添加职责。
  2. 处理那些可以撤销的职责。
  3. 当不能采用生成子类的方法进行扩充。
参与者
 
  1. Component:定义一个对象接口,可以给这些对象动态的添加职责。
  2. ConcreteComponent:定义一个对象,可以给这个对象添加一些职责。
  3. Decorator:维持一个指向Component对象的指针,并定义一个与Compinent接口一致的接口。
  4. ConcreteDecorator:向组件添加职责。

例子

//Component
public interface Person {
  void eat();
}
//ConcreteComponent
public class Man implements Person{
  @Override
  public void eat() {
    System.out.println("男人在吃");
  }
}
//Decorator
public abstract class Decorator implements Person {

  protected Person person;

  public void setPerson(Person person) {
    this.person = person;
  }

  @Override
  public void eat() {
    person.eat();
  }
}
//ConcreteDecorator
public class ManDecoratorA extends Decorator {
  @Override
  public void eat() {
    super.eat();
    reEat();
    System.out.println("ManDecoratorA 类");
  }

  public void reEat() {
    System.out.println("再吃一顿饭");
  }
}
//ConcreteDecorator
public class ManDecoratorB extends Decorator {

  @Override
  public void eat() {
    super.eat();
    System.out.println("===============");
    System.out.println("ManDecoratorB 类");
  }

}
//Test
public class Test {
  public static void main(String[] args) {
    Man man = new Man();
    ManDecoratorA manDecoratorA = new ManDecoratorA();
    ManDecoratorB manDecoratorB = new ManDecoratorB();

    manDecoratorA.setPerson(man);
    manDecoratorB.setPerson(manDecoratorA);
    manDecoratorB.eat();
    //男人在吃
    // 再吃一顿饭
    // ManDecoratorA 类
    //===============
    // ManDecoratorB 类
  }
}

 

2.10 外观模式

 

为子系统的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这个子系统更加容易使用。

适用性

  1. 当你要为一个复杂的子系统提供一个简单的接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更小更多的类。这使得子系统更具可重用性,也更容易对子系统进行定制,但这也给一些不需要定制子系统的的用户带来使用上的困难。Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过facade层。
  2. 客户程序与抽象类的实现部分之间存在着很大的依赖性。引入facade将这个子系统与客户以及其它的子系统分离,可以提高子系统的独立性和可移植性。
  3. 当你需要构建一个层次结构的子系统时,使用facade模式定义子系统中每层的入口点。如果子系统之间是相互依赖的,你可以让它们仅通过facade进行通讯,从而简化了它们之间的依赖。
参与者
 
  1. Facade:知道哪些子系统负责处理请求。将客户的请求代理给适当的子系统对象。
  2. Subsystemclasses:实现子系统的功能。处理由Facade对象指派的任务。没有facade的任何相关信息,即没有指向facade的指针。

例子

public interface ServiceA {
  void methodA();
}
public interface ServiceB {
  void methodB();
}
public interface ServiceC {
  void methodC();
}
//Facade
public class Facade {
  ServiceA sa;
  ServiceB sb;
  ServiceC sc;

  public Facade() {
    sa = new ServiceAImpl();
    sb = new ServiceBImpl();
    sc = new ServiceCImpl();
  }
  public void methodA() {
    sa.methodA();
    sb.methodB();
  }
  public void methodB() {
    sb.methodB();
    sc.methodC();
  }
  public void methodC() {
    sc.methodC();
    sa.methodA();
  }
}
//Subsystemclasses
public class ServiceAImpl implements ServiceA {
  @Override
  public void methodA() {
    System.out.println("这是服务 A");
  }
}
//Subsystemclasses
public class ServiceBImpl implements ServiceB {
  @Override
  public void methodB() {
    System.out.println("这是服务 B");
  }
}
//Subsystemclasses
public class ServiceCImpl implements ServiceC {
  @Override
  public void methodC() {
    System.out.println("这是服务 C");
  }
}
//Test
public class Test {

  public static void main(String[] args) {
    ServiceA sa = new ServiceAImpl();
    ServiceB sb = new ServiceBImpl();

    sa.methodA();//这是服务A
    sb.methodB();//这是服务B
    System.out.println("========");
    //facade
    Facade facade = new Facade();
    facade.methodA();//这是服务A//这是服务B
    facade.methodB();//这是服务B//这是服务C
  }
}

个人理解,外观模式,其实就是项目里的控制器。负责调用各个接口。接口的调用放在控制器来聚合。

 

2.11 享元模式

 

运用共享技术有效的支持大量细粒度的对象

适用性(当都具备下列情况时,使用Flyweight模式

  1. 一个程序大量使用对象
  2. 完全由于使用大量的对象,造成很大的存储开销。
  3. 对象的大多数状态都可变为外部状态。
  4. 如果删除对象的外部状态,那么可以用相对较少的共享对象取代很多组对象。
  5. 应用程序不依赖于对象标识。由于Flyweight对象可以被共享,对于概念上明显有别的对象,标识测试将返回真值。
参与者
 
  1. Flyweight:描述一个接口,通过这个接口flyweight可以接受并作用于外部状态。
  2. ConcreteFlyWeight:实现Flyweight接口,并为内部状态(如果有的话)增加内存空间。ConcreteFlyWeight对象必须是可共享的。它所存储的状态必须是内部的;即,它必须独立于ConcreteFlyWeight对象的场景。
  3. Unshared ConcreteFlyWeight:并未所有的Flyweight子类都需要被共享。FlyWeight接口使共享成为可能,但它并不强制共享。在Flyweight对象结构的某些层次,UnsharedConcreteFlyWeight对象通常将ConcreteFlyWeight对象作为子节点。
  4. FlyweightFactory:创建并管理Flyweight对象。确保合理地共享flyweight。当用户请求一个flyweight时,FlyweightFactory对象提供一个已创建的实例或者创建一个(如果不存在的话);

例子

//Flyweight
public interface Flyweight {
  void action(int arg);
}
//ConcreteFlyweight
public class FlyweightImpl implements Flyweight{
  @Override
  public void action(int arg) {
    System.out.println("参数值: " + arg);
  }
}
//FlyweightFactory
public class FlyweightFactory {
  private static Map flyweights = new HashMap();

  public static Flyweight getFlyweight(String key) {
    if (flyweights.get(key) == null) {
      flyweights.put(key, new FlyweightImpl());
    }
    return (Flyweight) flyweights.get(key);
  }

  public static int getSize() {
    return flyweights.size();
  }
}
//启动
public class Test {
  public static void main(String[] args) {
    Flyweight fly1 = FlyweightFactory.getFlyweight("a");
    fly1.action(1);//参数值: 1

    Flyweight fly2 = FlyweightFactory.getFlyweight("a");
    System.out.println(fly1 == fly2);//true

    Flyweight fly3 = FlyweightFactory.getFlyweight("b");
    fly3.action(3);//参数值: 3

    Flyweight fly4 = FlyweightFactory.getFlyweight("c");
    fly4.action(4);//参数值: 4

    Flyweight fly5 = FlyweightFactory.getFlyweight("d");
    fly4.action(4);//参数值: 4
    System.out.println(FlyweightFactory.getSize());//4
  }
}

个人理解:这里其实就是Spring容器,负责注入和管理各个实例。面试还有循环注入的问题,三级缓存的问题可以去学习下。

 

2.12 代理模式

 

为其他对象提供一种代理以控制对这个对象的访问。

适用性

  1. 远程代理(RemoteProxy)为一个对象在不同的地址空间提供局部代表。
  2. 虚代理(VirtualProxy)根据需求创建开销很大对象。
  3. 保护模式(ProtectionProxy)控制对原始对象的访问。
  4. 智能指引(SmartReference)取代了简单的指针,它在访问对象时执行一些附加操作。
参与者
 
  1. Proxy:保存一个引用使得代理可以访问实体。若realSubject和Subject的接口相同,Proxy会引用Subject。提供一个与Subject的接口相同的接口,这样代理就可以用来替代实体。控制对实体的存取,并可能负责创建和删除它。其他功能依赖于代理的原型。
  2. RemoteProxy :负责对请求及其参数进行编码,并向不同地址空间种的实体发送已编码的请求。
  3. VirtualProxy :可以缓存实体的附加信息,以便延迟对它的访问。
  4. ProtectionProxy:检查调用者是否具有实现一个请求所必需的访问权限。
  5. Subject:定义RealSubject和Proxy的共用接口,这样就在任何使用RealSubject的地方都可以使用Proxy。
  6. RealSubject:定义Proxy所代表的实体。

例子

//Subject
public interface Object {
  void action();
}
//RealSubject
public class ObjectImpl implements Object {
  @Override
  public void action() {
    System.out.println("========");
    System.out.println("========");
    System.out.println("这是被代理的类");
    System.out.println("========");
    System.out.println("========");
  }
}
//Proxy
public class ProxyObject implements Object {

  Object object;

  public ProxyObject() {
    System.out.println("这是代理类");
    object = new ObjectImpl();
  }

  @Override
  public void action() {
    System.out.println("代理开始");
    object.action();
    System.out.println("代理结束");
  }
}
//启动
public class Test {
  public static void main(String[] args) {
    Object object = new ProxyObject();
    object.action();
    /**
     * 这是代理类
     * 代理开始
     * ========
     * ========
     * 这是被代理的类
     * ========
     * ========
     * 代理结束
     */
  }
}

 

行为型模式

  • Chain of  Responsibility( 责任链模式 )
  • Command ( 命令模式 )
  • Interpreter ( 解释器模式 )
  • Iterator ( 迭代器模式 )
  • Mediator ( 中介者模式 )
  • Memento ( 备忘录模式 )
  • Observer ( 观察者模式 )
  • State( 状态模式 )
  • Strategy( 策略模式 )
  • TemplateMethod( 模板方法 )
  • Visitor( 访问者模式 )

 

2.13 责任链模式

 

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

适用性

  1. 有多个的对象可以处理一个请求,哪个对象处理该请求运行时刻自动确定。
  2. 你想在不明确指定接受者的情况下,向多个对象中一个提交一个请求。
  3. 可处理一个请求的对象集合应被动态指定。
参与者
 
  1. Handler:定义一个处理请求的接口。(可选)实现后继链。
  2. ConcreteHandler :处理它所负责的请求。可访问它的后继者。如果可处理该请求,就处理之;否则将该请求转发个它的后继者。
  3. Client :向链上的具体处理者(ConcreteHandler )对象提交请求。

例子

public class Request {}
//Handler
public interface RequestHandle {
  void handleRequest(Request request);
}
public class LeaveRequest extends Request {}
public class AddMoneyRequest extends Request {}
public class DimissionRequest extends Request {}
//ConcreteHandler
public class TLRequestHandle implements RequestHandle {
  RequestHandle rh;

  public TLRequestHandle(RequestHandle rh) {
    this.rh = rh;
  }

  @Override
  public void handleRequest(Request request) {
    if (request instanceof LeaveRequest) {
      System.out.println("要请假, 项目组长审批!");
    } else {
      rh.handleRequest(request);
    }
  }
}
//ConcreteHandler
public class PMRequestHandle implements RequestHandle {

  RequestHandle rh;

  public PMRequestHandle(RequestHandle rh) {
    this.rh = rh;
  }

  @Override
  public void handleRequest(Request request) {
    if (request instanceof AddMoneyRequest) { System.out.println("要加薪, 项目经理审批!");
    } else {
      rh.handleRequest(request); }
  }
}
//ConcreteHandler
public class TLRequestHandle implements RequestHandle {
  RequestHandle rh;

  public TLRequestHandle(RequestHandle rh) {
    this.rh = rh;
  }

  @Override
  public void handleRequest(Request request) {
    if (request instanceof LeaveRequest) {
      System.out.println("要请假, 项目组长审批!");
    } else {
      rh.handleRequest(request);
    }
  }
}

//ConcreteHandler
public class HRRequestHandle implements RequestHandle {

  @Override
  public void handleRequest(Request request) {
    if (request instanceof DimissionRequest) {
      System.out.println("要离职, 人事审批!");
    }System.out.println("请求完毕");
  }
}
//启动
// Client
public class Test {
  public static void main(String[] args) {
    RequestHandle hr = new HRRequestHandle();
    RequestHandle pm = new PMRequestHandle(hr);
    RequestHandle tl = new TLRequestHandle(pm);

    //team leader 处理离职请求
    Request request = new DimissionRequest();
    tl.handleRequest(request);
    System.out.println("===========");
    //team leader 处理加薪请求
    request = new AddMoneyRequest();
    tl.handleRequest(request);
    System.out.println("========");
    //项目经理上理辞职请求
    request = new DimissionRequest();
    pm.handleRequest(request);
  }
}

 

2.14 命令模式

 

将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或纪录请求日志,以及支持可撤销的动作。

适用性

  1. 抽象出待执行的动作以参数化某对象。
  2. 在不同的时刻指定、排列和执行请求。
  3. 支持取消操作。
  4. 支持修改日志,这样当系统崩溃时,这次修改可以重做一遍。
  5. 用构建在原语操作上的高层操作构造一个系统。
参与者
 
  1. Command:声明执行操作的接口。
  2. ConcreteCommand :将一个接收者对象绑定于一个动作。调用接收者相应的操作,以实现Execute。
  3. Client :创建一个具体的命令对象并设置它的接收者
  4. Invoker:要求该命令执行这个请求。
  5. Receiver:知道如何实现与执行一个请求相关的操作。任何类都可能作为一个接收者。

例子

//Receiver
public class Receiver {
  public void receive() {
    System.out.println("This is Receive class!");
  }
}
//Command
public abstract class Command {
  protected Receiver receiver;

  public Command(Receiver receiver) {
    this.receiver = receiver;
  }
  public abstract void execute();
}
public class CommandImpl extends Command{
  public CommandImpl(Receiver receiver) {
    super(receiver);
  }

  @Override
  public void execute() {
    receiver.receive();
  }
}
//Invoker
public class Invoker {
  private Command command;
  public void setCommand(Command command) { this.command = command; }

  public void execute() {
    command.execute();
  }
}
//启动
public class Test {
  public static void main(String[] args) {
    Receiver rec = new Receiver();
    Command cmd = new CommandImpl(rec);
    Invoker i = new Invoker();
    i.setCommand(cmd);
    i.execute();
  }
}

 

2.15 解释器模式

 

给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。

适用性

当有一个语言需要解释执行,并且你可将该语言中的句子表示为一个抽象语法树时,可使用解释器模式。而当存在以下情况时该模式效果最好:

  1. 该文法简单对于复杂的文法,文法的类层次变得庞大而无法管理。
  2. 效率不是一个关键问题最高效的解释器通常不是通过直接解释语法分析树实现的,而是首先将它们转换成另一种新式。
参与者
 
  1. AbstractExpression( 抽象表达式 ):声明一个抽象的解释操作,这个接口为抽象语法树中所有的节点所共享。
  2. TerminalExpression( 终结符表达式 ) :实现与文法中的终结符相关联的解释操作。一个句子中的每个终结符需要该类的一个实例。
  3. NonTerminalExpression( 非终结符表达式 ) :为文法中的非终结符实现解释(Interpret)操作。
  4. Context( 上下文 ):包含解释器之外的一些全局信息。
  5. Client( 客户端 ):构建(或被给定)表示该文法定义的语言中一个特定的句子的抽象语法树。该抽象语法树由NonTerminalExpression和TerminalExpression的实例装配而成。调用解释操作。

例子

//AbstractExpression
public abstract class Expression {
  abstract void interpret(Context ctx);
}
//Expression
public class AdvanceExpression extends Expression{
  @Override
  void interpret(Context ctx) {
    System.out.println("这是高级解析器!");
  }
}
//Expression
public class SimpleExpression extends Expression{
  @Override
  void interpret(Context ctx) {
    System.out.println("这是普通解析器!");
  }
}
//Context
public class Context {

  private String content;
  List<Expression> list = new ArrayList();

  public void setContent(String content) {
    this.content = content;
  }

  public String getContent() {
    return this.content;
  }

  public void add(Expression eps) {
    list.add(eps);
  }

  public List<Expression> getList() {
    return list;
  }
}
//启动
public class Text {
  public static void main(String[] args) {
    Context ctx = new Context();
    ctx.add(new SimpleExpression());
    ctx.add(new AdvanceExpression());
    ctx.add(new SimpleExpression());
    for (Expression eps : ctx.getList()) {
      eps.interpret(ctx);
    }
    /**
     * 这是普通解析器!
     * 这是高级解析器!
     * 这是普通解析器!
     */
  }
}

 

2.16 迭代器模式

 

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

适用性

  1. 访问一个聚合对象的内容无需暴露它的内部表示。
  2. 支持对聚合对象的多种遍历。
  3. 为遍历不同的聚合结构提供一个统一的接口( 即,支持多态迭代 )
参与者
 
  1. Iterator:迭代器定义访问和遍历元素的接口。
  2. ConcreteIterator :具体迭代器实现迭代器接口。对该聚合遍历时跟踪当前位置。
  3. Aggregate:聚合定义创建相应迭代器对象的接口。
  4. ConcreteAggregate:具体聚合实现创建相应迭代器的接口,该操作返回ConcerteIterator的一个适当的实例。

例子

//Aggregate
public interface List {
  Iterator iterator();
  Object get(int index);
  int getSize();
  void add(Object obj);
}
//ConcreteAggregate
public class ListImpl implements List {

  private Object[] list;
  private int index;
  private int size;

  public ListImpl() {
    index = 0;
    size = 0;
    list = new Object[100];
  }

  @Override
  public Iterator iterator() {
    return new IteratorImpl(this);
  }

  @Override
  public Object get(int index) {
    return list[index];
  }

  @Override
  public int getSize() {
    return this.size;
  }

  @Override
  public void add(Object obj) {
    list[index++] = obj;
    size++;
  }
}
//Iterator
public interface Iterator {
  Object next();
  void first();
  void last();
  boolean hasNext();
}
//ConcreteIterator
public class IteratorImpl implements Iterator{
  private List list;
  private int index;

  public IteratorImpl(List list) {
    this.index = 0;
    this.list = list;
  }

  @Override
  public Object next() {
    Object obj = list.get(index);
    index++;
    return obj;
  }

  @Override
  public void first() {
    this.index = 0;
  }

  @Override
  public void last() {
    this.index = list.getSize();
  }

  @Override
  public boolean hasNext() {
    return index < list.getSize();
  }
}
//启动
public class Test {
  public static void main(String[] args) {
    List list = new ListImpl();
    list.add("a");
    list.add("b");
    list.add("c");
    //第一种迭代方式
    Iterator iterator = list.iterator();
    while (iterator.hasNext()) {
      System.out.println(iterator.next());
    }
    System.out.println("======");
    //第二种迭代方式
    for (int i = 0; i < list.getSize(); i++) {
      System.out.println(list.get(i));
    }
  }
}

 

2.17 中介者模式

 

用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变他们之间地交互。

适用性

  1. 一组对象以定义良好但是复杂地方式进行通信。产生地相互依赖关系结构混乱且难以理解。
  2. 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
  3. 想定制一个分布在多个类中地行为,而又不想生成太多地子类。
参与者
 
  1. Mediator:中介者定义一个接口用于与各同事( Colleague )对象通信。
  2. ConcreteMediator:具体中介者通过协调各同事对象实现协作行为 。了解并维护它的各个同事。
  3. Colleagueclass:每一个同事类都知道它的中介者对象。每一个同事对象在需与其他同事通信地时候先与它的中介者通信。

例子

public abstract class Colleague {
  abstract void action();
}
//Colleagueclass
public class ColleagueA extends Colleague {
  @Override
  public void action() {
    System.out.println("普通员工努力工作");
  }
}
//Colleagueclass
public class ColleagueB extends Colleague {
  @Override
  public void action() {
    System.out.println("前台注意了!");
  }
}
//Mediator
public abstract class Mediator {
  public abstract void notice(String content);
}
//ConcreteMediator
public class ConcreteMediator extends Mediator {

  private ColleagueA ca;
  private ColleagueB cb;

  public ConcreteMediator() {
    this.ca = new ColleagueA();
    this.cb = new ColleagueB();
  }

  @Override
  public void notice(String content) {
    if (content.equals("boss")) { //老板来了, 通知员工 A
      ca.action();
    }
    if (content.equals("client")) {
      //客户来了, 通知知前台 B
      cb.action();
    }
  }
}
//启动
public class Test {

  public static void main(String[] args) {
    Mediator med = new ConcreteMediator(); //老板来了
    med.notice("boss");//普通员工努力工作
    //客户来了
    med.notice("client");//前台注意了!
  }
}

 

2.18 备忘录模式

 

在不破坏封装性地前提下,捕获一个对象地内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。

适用性

  1. 必须保存一个对象地在某一时刻的(部分)状态,这样以后需要时它才能恢复到先前的状态。
  2. 如果一个用接口来让其它对象直接得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
参与者
 
  1. Memento:备忘录存储原发器对象的内部状态。
  2. Originator:原发器创建一个备忘录,用以纪录当前时刻中的内部状态。使用备忘录恢复内部状态。
  3. Caretaker:负责保存好备忘录。不能对备忘录的内容进行操作或检查。

例子

public class Memento {
  private String state;

  public String getState() {
    return state;
  }

  public void setState(String state) {
    this.state = state;
  }

  public Memento(String state) {
    this.state = state;
  }
}
public class Originator {
  private String state;

  public String getState() {
    return state;
  }

  public void setState(String state) {
    this.state = state;
  }

  public Memento createMemento() { return new Memento(state);
  }
  public void setMemento(Memento memento) {
    state = memento.getState(); }
  public void showState(){ System.out.println(state);
  }
}
public class Caretaker {

  private Memento memento;

  public Memento getMemento() {
    return this.memento;
  }

  public void setMemento(Memento memento) {
    this.memento = memento;
  }
}
public class Test {
  public static void main(String[] args) {
    Originator org = new Originator();
    org.setState("开会中");
    Caretaker ctk = new Caretaker();
    ctk.setMemento(org.createMemento());//将数据封装在 Caretaker
    org.setState("睡觉中");
    org.showState();//睡觉中
    org.setMemento(ctk.getMemento());//将数据重新导入
    org.showState();//开会中,上次保存的
  }
}

 

2.19 观察者模式

 

定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。

适用性

  1. 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面。将这二者封装在独立的对象中以使它们可以各自独立地改变和复用。
  2. 当对一个对象的改变需要同时改变其它对象,而不知道具体的多少对象有待改变。
  3. 当一个对象对象必须通知其它对象,而它又不能假定其它对象是谁。
参与者
 
  1. Subject(目标):目标知道它的观察者。可以有任意多个观察者观察同一对象。提供注册和删除观察者对象的接口。
  2. Observer(观察者):为那些在目标发生改变时需获得通知的对象定义一个更新接口。
  3. ConcreteSubject(具体目标):将有关状态存入各ConcreteSubject对象。当它的状态发生改变时,向它的各个观察者发出通知。
  4. ConcreteObserver(具体观察者):维护一个指向 ConcreteSubject对象的引用。存储有关状态,这些状态应与目标的状态保持一致。实现Observer的更新接口能使自身状态与目标状态保持一致。

例子

//Subject
public abstract class Citizen {

  List<Policeman> pols;

  String help = "normal";

  public void setHelp(String help) {
    this.help = help;
  }

  public String getHelp() {
    return this.help;
  }

  abstract void sendMessage(String help);

  public void setPolicemen() {
    this.pols = new ArrayList();
  }

  public void register(Policeman pol) {
    this.pols.add(pol);
  }

  public void unRegister(Policeman pol) {
    this.pols.remove(pol);
  }
}
//Observer
public interface Policeman {
  void action(Citizen ci);
}
//ConcreteSubject
public class HuangPuCitizen extends Citizen {

  public HuangPuCitizen(Policeman pol) {
    setPolicemen();
    register(pol);
  }

  @Override
  void sendMessage(String help) {
    setHelp(help);
    for (int i = 0; i < pols.size(); i++) {
      Policeman pol = pols.get(i);
      //通知警察行动
      pol.action(this);
    }
  }
}
//ConcreteSubject
public class TianHeCitizen extends Citizen {

  public TianHeCitizen(Policeman pol) {
    setPolicemen();
    register(pol);
  }

  @Override
  void sendMessage(String help) {
    setHelp(help);
    for (int i = 0; i < pols.size(); i++) {
      Policeman pol = pols.get(i);
      //通知警察行动 
      pol.action(this);
    }
  }
}
//ConcreteObserver
public class HuangPuPoliceman implements Policeman {
  @Override
  public void action(Citizen ci) {
    String help = ci.getHelp();
    if ("normal".equals(help)) {
      System.out.println("一切正常, 不用出动");
    }
    if ("unnormal".equals(help)) {
      System.out.println("有犯罪行为, 黄埔警察出动!");
    }
  }
}
//ConcreteObserver
public class TianHePoliceman implements Policeman {
  @Override
  public void action(Citizen ci) {
    String help = ci.getHelp();
    if ("normal".equals(help)) {
      System.out.println("一切正常, 不用出动");
    }
    if ("unnormal".equals(help)) {
      System.out.println("有犯罪行为, 天河警察出动!");
    }
  }
}
public class Test {
  public static void main(String[] args) {
    Policeman thPol = new TianHePoliceman();
    Policeman hpPol = new HuangPuPoliceman();

    Citizen citizen = new HuangPuCitizen(hpPol);
    citizen.sendMessage("unnormal");
    citizen.sendMessage("normal");
    System.out.println("===========");
    citizen = new TianHeCitizen(thPol);
    citizen.sendMessage("normal");
    citizen.sendMessage("unnormal");
  }
}

 

2.20 状态模式

 

具体状态的行为在具体的状态类中就解决,不用交给外部做判断。实质是将多条件判断弄成了多个类,在不同的类中做判断。

适用性

  1. 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
  2. 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。这个状态通常用一个或多个枚举常量表示。通常,有多个操作包含这一相同的条件结构。State模式将每一个条件分支放如一个独立的类中。这使得你可以根据对象自身的情况将对象的状态作为一个对象,这一对象可以不依赖于其它对象而独立变化。
参与者
 
  1. Context:定义客户感兴趣的接口。维护一个ConcreteState子类的实例,这个实例定义当前状态。
  2. State:定义一个接口以封装与Context的一个特定状态相关的行为。
  3. ConcreteStatesubclasses:每一个子类实现一个与Context的一个状态相关的行为。

例子

//State
public interface Weather {
  String getWeather();
}
public class Context {

  private Weather weather;
  public void setWeather(Weather weather) {
    this. weather = weather;
  }

  public Weather getWeather() {
    return this.weather;
  }

  public String weatherMessage() {
    return weather.getWeather();
  }
}
//ConcreteStatesubclasses
public class Rain implements Weather{
  @Override
  public String getWeather() {
    return "下雨";
  }
}
//ConcreteStatesubclasses
public class Sunshine implements Weather{
  @Override
  public String getWeather() {
    return "阳光";
  }
}
public class Test {
  public static void main(String[] args) {
    Context ctx1 = new Context();
    ctx1.setWeather(new Sunshine());
    System.out.println(ctx1.weatherMessage());//阳光
    System.out.println("===============");
    Context ctx2 = new Context();
    ctx2.setWeather(new Rain());
    System.out.println(ctx2.weatherMessage());//下雨
  }
}

 

2.21 策略模式

 

定义一系列的算法,把它们个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的客户而变化。

适用性

  1. 许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。
  2. 需要使用一个算法的不同变体。
  3. 算法使用客户不应该知道的数据。可使用策略模式以避免暴露复杂的、与运算相关的数据结构。
  4. 一个类定义了多种行为,并且这些行为在这个类的操作以多个条件语句的形式出现。将相关的条件分支移入它们各自的Strategy类中以代替这些条件。
参与者
 
  1. Strategy:定义所有支持的算法的公共接口。Context使用这个接口来调用某ConcreteStrategy定义的算法。
  2. ConcreteStrategy:以Strategy接口实现某具体算法。
  3. Context:用一个ConcreteStrategy对象来配置。维护一个对Strategy对象的引用。可定义一个接口来让Strategy访问它的数据。

例子

public abstract class Strategy {
  public abstract void method();
}
//ConcreteStrategy
public class StrategyImplA extends Strategy{
  @Override
  public void method() {
    System.out.println("这是第一个实现");
  }
}
public class StrategyImplB extends Strategy{
  @Override
  public void method() {
    System.out.println("这是第二个实现");
  }
}
public class StrategyImplC extends Strategy{
  @Override
  public void method() {
    System.out.println("这是第三个实现");
  }
}
public class Context {

  Strategy stra;
  public Context(Strategy stra) {
    this.stra = stra;
  }

  public void doMethod() {
    stra.method();
  }
}
public class Test {
  public static void main(String[] args) {
    Context ctx = new Context(new StrategyImplA());
    ctx.doMethod();//这是第一个实现
    ctx = new Context(new StrategyImplB());
    ctx.doMethod();//这是第二个实现
    ctx = new Context(new StrategyImplC());
    ctx.doMethod();//这是第三个实现
  }
}

 

2.22 模板方法

 

定义一个操作中的算法骨架,而将一些步骤延迟到子类中。TemplateMethod使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。

适用性

  1. 一次性实现一个算法的不变的部分,并将可变的行为留给子类来实现。
  2. 各子类中公共的行为应该被提取出来并集中到一个公共父类之中以避免代码重复。
    首先识别现有代码中的不同之处,并且将不同之处分离为新的操作。
    最后,用一个调用这些新的操作的模板方法来替换这些不同的代码。
  3. 控制子类扩展。
参与者
 
  1. AbstractClass:定义抽象的原语操作(primitiveoperation),具体的子类将重定义它们以实现一个算法的各步骤。
    实现一个模板方法,定义一个算法骨架。
    该模板方法不仅调用原语操作,也调用定义在AbstractClass或其它对象中的操作。
  2. ConcreteClass:实现原语操作以完成算法中与特定子类相关的步骤。

例子

//AbstractClass
public abstract class Template {
  public abstract void print();

  public void update() {
    System.out.println("开始打印");
    for (int i = 0; i < 10; i++) {
      print();
    }
  }
}
//ConcreteClass
public class TemplateConcrete extends Template{
  @Override
  public void print() {
    System.out.println("这是子类的实现");
  }
}
public class Test {
  public static void main(String[] args) {
    Template temp = new TemplateConcrete();
    temp.update();
  }
}

 

2.23 访问者模式

 

表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。

适用性

  1. 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
  2. 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免这些操作“污染”这些对象的类。
    Visitor使得你可以将相关的操作集中起来定义在一个类中。
    当该对象结构被很多应用共享时,用Visitor模式让每个应用仅包含需要用到的操作。
  3. 定义对象结构的类很少改变,但经常需要在此结构上定义新的操作。
    改变对象结构类需要重定义对所有访问者的接口,这可能需要很大的代价。
    如果对象结构类经常改变,那么可能还是在这些类中定义这些操作较好。
参与者
 
  1. Visitor:为该对象结构中ConcreteElement的每一个类声明一个Visit操作。
    该操作的名字和特征标识了发送Visit请求给该访问者的那个类。
    这使得访问者可以确定正在访问元素的具体的类。
    这样访问者就可以通过该元素的特定接口直接访问它。
  2. ConcreteVisitor:实现每个由Visitor声明的操作。
    每个操作实现本算法的一部分,而该算法片段乃是对应于结构中对象的类。
    ConcreteVisitor为该算法提供了上下文并存储它的局部状态。
    这一状态常常在遍历该结构的过程中累计结果。
  3. Element:定义一个Accept操作,它以一个访问者为参数。
  4. ConcreteElement:实现一个Accept操作,该操作以一个访问者为参数。
  5. ObjectStructure:能枚举它的元素。可以提供一个高层的接口以允许该访问者访问它的元素。可以是一个复合或是一个集合,如一个列表或一个无序集合。

例子

public interface Visitor {

  public void visitString(StringElement stringE);

  public void visitFloat(FloatElement floatE);

  public void visitCollection(Collection collection);
}
public class ConcreteVisitor implements Visitor {

  @Override
  public void visitString(StringElement stringE) {
    System.out.println(stringE.getSe());
  }

  @Override
  public void visitFloat(FloatElement floatE) {
    System.out.println(floatE.getFe());
  }

  @Override
  public void visitCollection(Collection collection) {
    Iterator iterator = collection.iterator();
    while (iterator.hasNext()) {
      Object o = iterator.next();
      if (o instanceof Visitable){
        ((Visitable)o).accept(this);
      }
    }
  }
}
//Element
public interface Visitable {
  public void accept(Visitor visitor);
}
//ConcreteElement
public class FloatElement implements Visitable {

  private Float fe;

  public FloatElement(Float fe) {
    this.fe = fe;
  }

  public Float getFe() {
    return this.fe;
  }

  @Override
  public void accept(Visitor visitor) {
    visitor.visitFloat(this);
  }
}
//ConcreteElement
public class StringElement implements Visitable {

  private String se;

  public StringElement(String se) {
    this.se = se;
  }

  public String getSe() { return this.se; }

  @Override
  public void accept(Visitor visitor) {
    visitor.visitString(this);
  }
}
public class Test {
  public static void main(String[] args) {
    Visitor visitor = new ConcreteVisitor();
    StringElement se = new StringElement("abc");
    se.accept(visitor);//abc
    FloatElement fe = new FloatElement(1.5f);
    fe.accept(visitor);//1.5
    System.out.println("===========");
    List result = new ArrayList();
    result.add(new StringElement("abc"));
    result.add(new StringElement("abc"));
    result.add(new StringElement("abc"));
    result.add(new FloatElement(1.5f));
    result.add(new FloatElement(1.5f));
    result.add(new FloatElement(1.5f));
    visitor.visitCollection(result);
    /**
     * abc
     * abc
     * abc
     * 1.5
     * 1.5
     * 1.5
     */
  }
}

 

3. 总结

经过三天的时间总算是敲完了所有文字了代码。每一个都跑通了。没理解的也自己debug慢慢研究了。囫囵吞枣毕竟不好,接下来有空希望自己多看看文章,回忆一下。

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值