设计模式笔记

前言

设计模式是为了让代码的编写和理解更加简单而产生的.
内容基本使用了菜鸟教程,其他参考请见结尾.

设计模式分类

23种设计模式,三大类
创建型模式
结构型模式
行为型模式
若按照业务上来分类,还有J2EE设计模式

序号 模式 & 描述 包括
1 *创建型模式*这些设计模式提供了一种在创建对象的同时隐藏创建逻辑的方式,而不是使用 new 运算符直接实例化对象。这使得程序在判断针对某个给定实例需要创建哪些对象时更加灵活。 工厂模式(Factory Pattern)抽象工厂模式(Abstract Factory Pattern)单例模式(Singleton Pattern)建造者模式(Builder Pattern)原型模式(Prototype Pattern)
2 *结构型模式*这些设计模式关注类和对象的组合。继承的概念被用来组合接口和定义组合对象获得新功能的方式。 适配器模式(Adapter Pattern)桥接模式(Bridge Pattern)过滤器模式(Filter、Criteria Pattern)组合模式(Composite Pattern)装饰器模式(Decorator Pattern)外观模式(Facade Pattern)享元模式(Flyweight Pattern)代理模式(Proxy Pattern)
3 *行为型模式*这些设计模式特别关注对象之间的通信。 责任链模式(Chain of Responsibility Pattern)命令模式(Command Pattern)解释器模式(Interpreter Pattern)迭代器模式(Iterator Pattern)中介者模式(Mediator Pattern)备忘录模式(Memento Pattern)观察者模式(Observer Pattern)状态模式(State Pattern)空对象模式(Null Object Pattern)策略模式(Strategy Pattern)板模式(Template Pattern)访问者模式(Visitor Pattern)
4 *J2EE 模式*这些设计模式特别关注表示层。这些模式是由 Sun Java Center 鉴定的。 MVC 模式(MVC Pattern)业务代表模式(Business Delegate Pattern)组合实体模式(Composite Entity Pattern)数据访问对象模式(Data Access Object Pattern)前端控制器模式(Front Controller Pattern)拦截过滤器模式(Intercepting Filter Pattern)服务定位器模式(Service Locator Pattern)传输对象模式(Transfer Object Pattern)

设计模式的原则

1、开闭原则(Open Close Principle)
开闭原则的意思是:*对扩展开放,对修改关闭*。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。简言之,是为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。
2、里氏代换原则(Liskov Substitution Principle)
里氏代换原则是面向对象设计的基本原则之一。
里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。LSP
是继承复用的基石,只有当派生类可以替换掉基类,且软件单位的功能不受到影响时,基类才能真正被复用,而派生类也能够在基类的基础上增加新的行为。里氏代换原则是对开闭原则的补充。实现开闭原则的关键步骤就是抽象化,而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。
3、依赖倒转原则(Dependence Inversion Principle)
这个原则是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
4、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
5、迪米特法则,又称最少知道原则(Demeter Principle)
最少知道原则是指:一个实体应当尽量少地与其他实体之间发生相互作用,使得系统功能模块相对独立。
6、合成复用原则(Composite Reuse Principle)
合成复用原则是指:尽量使用合成/聚合的方式,而不是使用继承。

创造型模式

主要用于创建对象时使用

工厂模式

  1. 概括

    提前定义好类,并在工厂类中设置配置好生成类的接口,使用类的名字返回类

  2. 优点

    不暴露类的创建逻辑,适合复杂对象的创建

  3. 缺点

    需要新的类时需要增加的是实现类,需要更改工厂类中的接口

  4. 使用场景

    类的创建比较复杂时.
    比如设计一个连接服务器的框架,需要三个协议,“POP3”、“IMAP”、“HTTP”,可以把这三个作为产品类,共同实现一个接口

  5. 举例

    创建一个接口

    1
    2
    3
    public interface Shape {
    void draw();
    }

    创建接口的实现类

    1
    2
    3
    4
    5
    6
    public class Rectangle implements Shape {
    @Override
    public void draw() {
    System.out.println("Inside Rectangle::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Square implements Shape {
    @Override
    public void draw() {
    System.out.println("Inside Square::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Circle implements Shape {
    @Override
    public void draw() {
    System.out.println("Inside Circle::draw() method.");
    }
    }

    创建*工厂类*(主要)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class ShapeFactory {
    //使用 getShape 方法获取形状类型的对象
    public Shape getShape(String shapeType){
    if(shapeType == null){
    return null;
    }
    if(shapeType.equalsIgnoreCase("CIRCLE")){
    return new Circle();
    } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
    return new Rectangle();
    } else if(shapeType.equalsIgnoreCase("SQUARE")){
    return new Square();
    }
    return null;
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class FactoryPatternDemo {
    public static void main(String[] args) {
    ShapeFactory shapeFactory = new ShapeFactory();
    //获取 Circle 的对象,并调用它的 draw 方法
    Shape shape1 = shapeFactory.getShape("CIRCLE");
    //调用 Circle 的 draw 方法
    shape1.draw();
    //获取 Rectangle 的对象,并调用它的 draw 方法
    Shape shape2 = shapeFactory.getShape("RECTANGLE");
    //调用 Rectangle 的 draw 方法
    shape2.draw();
    //获取 Square 的对象,并调用它的 draw 方法
    Shape shape3 = shapeFactory.getShape("SQUARE");
    //调用 Square 的 draw 方法
    shape3.draw();
    }
    }

抽象工厂模式

  1. 概括

    为工厂类建立一个工厂(抽象工厂),多个例子属于一个产品族

  2. 优点

    方便类的创建后的管理,保证类都是同一类,不怕搞混

  3. 缺点

    需要增加产品时需要更改工厂类,
    需要增加工厂时需要更改抽象工厂类

  4. 使用场景

    QQ换皮肤,一整套一起换

  5. 举例

    两个接口

    1
    2
    3
    public interface Shape {
    void draw();
    }
    1
    2
    3
    public interface Color {
    void fill();
    }

    六个实现类

    1
    2
    3
    4
    5
    6
    public class Rectangle implements Shape {
    @Override
    public void draw() {
    System.out.println("Inside Rectangle::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Square implements Shape {
    @Override
    public void draw() {
    System.out.println("Inside Square::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Circle implements Shape {
    @Override
    public void draw() {
    System.out.println("Inside Circle::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Red implements Color {
    @Override
    public void fill() {
    System.out.println("Inside Red::fill() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Green implements Color {
    @Override
    public void fill() {
    System.out.println("Inside Green::fill() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Blue implements Color {
    @Override
    public void fill() {
    System.out.println("Inside Blue::fill() method.");
    }
    }

    *抽象工厂*(主要1)
    是一个抽象类

    1
    2
    3
    4
    public abstract class AbstractFactory {
    public abstract Color getColor(String color);
    public abstract Shape getShape(String shape) ;
    }

    两个实际的*工厂类*(主要2)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class ShapeFactory extends AbstractFactory {
    @Override
    public Shape getShape(String shapeType){
    if(shapeType == null){
    return null;
    }
    if(shapeType.equalsIgnoreCase("CIRCLE")){
    return new Circle();
    } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
    return new Rectangle();
    } else if(shapeType.equalsIgnoreCase("SQUARE")){
    return new Square();
    }
    return null;
    }
    @Override
    public Color getColor(String color) {
    return null;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class ColorFactory extends AbstractFactory {
    @Override
    public Shape getShape(String shapeType){
    return null;
    }
    @Override
    Color getColor(String color) {
    if(color == null){
    return null;
    }
    if(color.equalsIgnoreCase("RED")){
    return new Red();
    } else if(color.equalsIgnoreCase("GREEN")){
    return new Green();
    } else if(color.equalsIgnoreCase("BLUE")){
    return new Blue();
    }
    return null;
    }
    }

    要有创建工厂类用的接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class FactoryProducer {
    public static AbstractFactory getFactory(String choice){
    if(choice.equalsIgnoreCase("SHAPE")){
    return new ShapeFactory();
    } else if(choice.equalsIgnoreCase("COLOR")){
    return new ColorFactory();
    }
    return null;
    }
    }

    使用

    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
    public class AbstractFactoryPatternDemo {
    public static void main(String[] args) {
    //获取形状工厂
    AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
    //获取形状为 Circle 的对象
    Shape shape1 = shapeFactory.getShape("CIRCLE");
    //调用 Circle 的 draw 方法
    shape1.draw();
    //获取形状为 Rectangle 的对象
    Shape shape2 = shapeFactory.getShape("RECTANGLE");
    //调用 Rectangle 的 draw 方法
    shape2.draw();
    //获取形状为 Square 的对象
    Shape shape3 = shapeFactory.getShape("SQUARE");
    //调用 Square 的 draw 方法
    shape3.draw();
    //获取颜色工厂
    AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
    //获取颜色为 Red 的对象
    Color color1 = colorFactory.getColor("RED");
    //调用 Red 的 fill 方法
    color1.fill();
    //获取颜色为 Green 的对象
    Color color2 = colorFactory.getColor("Green");
    //调用 Green 的 fill 方法
    color2.fill();
    //获取颜色为 Blue 的对象
    Color color3 = colorFactory.getColor("BLUE");
    //调用 Blue 的 fill 方法
    color3.fill();
    }
    }

    为了方便才使用了静态方法创建的工厂,不然可以使用方法来创建工厂类

单例模式

  1. 概括

    一个类必须有且只有一个对象,并提供给其他类访问的接口.
    判断系统是否已经有这个单例,如果有则返回,如果没有则创建。

  2. 优点

    避免了过多的对象的创建和销毁
    减少了内存的开销
    避免了对资源的抢占

  3. 缺点

    不能继承
    与单一职责原则冲突

  4. 使用场景

    生产唯一的序列号
    计数器
    数据库连接

  5. 举例

    类的创建

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class SingleObject {
    //创建 SingleObject 的一个对象
    private static SingleObject instance = new SingleObject();
    //让构造函数为 private,这样该类就不会被实例化
    private SingleObject(){}
    //获取唯一可用的对象
    public static SingleObject getInstance(){
    return instance;
    }
    public void showMessage(){
    System.out.println("Hello World!");
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class SingletonPatternDemo {
    public static void main(String[] args) {
    //不合法的构造函数
    //编译时错误:构造函数 SingleObject() 是不可见的
    //SingleObject object = new SingleObject();
    //获取唯一可用的对象
    SingleObject object = SingleObject.getInstance();
    //显示消息
    object.showMessage();
    }
    }

    注意使用了private的构造函数时导致的=new SingleObject()=不可用的现象
    第一次使用=getInstance=时,在类的内部创建了一次对象,此后对象在类的内部,使用=getInstance()=时直接返回了

  6. 不同的实现方式

    1. 线程不安全

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public class Singleton {  
      private static Singleton instance;
      private Singleton (){}
      public static Singleton getInstance() {
      if (instance == null) {
      instance = new Singleton();
      }
      return instance;
      }
      }

      内部写了检测是否有对象的逻辑
      但是没有多线程下的安全保障(在判断null时另一个对象也在判断null

    2. 线程安全

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      public class Singleton {  
      private static Singleton instance;
      private Singleton (){}
      public static synchronized Singleton getInstance() {
      if (instance == null) {
      instance = new Singleton();
      }
      return instance;
      }
      }

      使用了=synchronized=,多线程下可以工作,但是性能受到了影响

    3. 饿汉模式

      1
      2
      3
      4
      5
      6
      7
      public class Singleton {  
      private static Singleton instance = new Singleton();
      private Singleton (){}
      public static Singleton getInstance() {
      return instance;
      }
      }

      在类装载时就初始化了实例
      基于classloader机制(类的加载器看类是否已经加载来提供类,若已加载,直接返回类)保证了多线程的安全,效率也高
      有很多情况导致类重新装载,产生垃圾对象

    4. 双重校验锁DCL(Double-Checked Locking)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      public class Singleton {  
      private volatile static Singleton singleton;
      private Singleton (){}
      public static Singleton getSingleton() {
      if (singleton == null) {
      synchronized (Singleton.class) {
      if (singleton == null) {
      singleton = new Singleton();
      }
      }
      }
      return singleton;
      }
      }

      使用两个 ==null 的判断,
      在大部分的情况下可以只使用第一层,多线程时有可能使用第二层,所以线程安全且性能较好

    5. 静态内部类

      1
      2
      3
      4
      5
      6
      7
      8
      9
      public class Singleton {  
      private static class SingletonHolder {
      private static final Singleton INSTANCE = new Singleton();
      }
      private Singleton (){}
      public static final Singleton getInstance() {
      return SingletonHolder.INSTANCE;
      }
      }

      使用内部类的方法来创建外部的类
      也是使用classloader的机制保证唯一性,
      不同的是需要人为使用getInstance方法(此时才会加载SingletonHolder类,比Singleton类的初始化要延迟一点)才会创建实例

    6. 枚举

      1
      2
      3
      4
      5
      public enum Singleton {  
      INSTANCE;
      public void whateverMethod() {
      }
      }

      一般可以使用饿汉模式,在需要延迟初始化时使用静态内部类,有特殊要求可以使用双重校验锁的方法,枚举的方法最好,但用的人少

建造者模式

  1. 概括

    复杂类由多个有共同点的部分组成,组成部分可以改变但组成的方法大致不变时使用组装的方式建立新的对象

  2. 优点

    容易扩展

  3. 缺点

    需要新建的对象有共同点(稳定的接口)

  4. 使用场景

    菜单中基础单品许多,但套餐不同,为了输出套餐的对象,使用建造者模式

  5. 举例

    创建一个表示食物条目和食物包装的接口。

    1
    2
    3
    4
    5
    public interface Item {
    public String name();
    public Packing packing();
    public float price();
    }
    1
    2
    3
    public interface Packing {
    public String pack();
    }

    所有的实物都有同样的方法,所以为该方法建立两个抽象类

    1
    2
    3
    4
    5
    6
    7
    8
    public abstract class Burger implements Item {
    @Override
    public Packing packing() {
    return new Wrapper();
    }
    @Override
    public abstract float price();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    public abstract class ColdDrink implements Item {
    @Override
    public Packing packing() {
    return new Bottle();
    }
    @Override
    public abstract float price();
    }

    包装方法只有两种,直接使用实体类

    1
    2
    3
    4
    5
    6
    public class Wrapper implements Packing {
    @Override
    public String pack() {
    return "Wrapper";
    }
    }
    1
    2
    3
    4
    5
    6
    public class Bottle implements Packing {
    @Override
    public String pack() {
    return "Bottle";
    }
    }

    食物的实体类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class VegBurger extends Burger {
    @Override
    public float price() {
    return 25.0f;
    }
    @Override
    public String name() {
    return "Veg Burger";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class ChickenBurger extends Burger {
    @Override
    public float price() {
    return 50.5f;
    }
    @Override
    public String name() {
    return "Chicken Burger";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Coke extends ColdDrink {
    @Override
    public float price() {
    return 30.0f;
    }
    @Override
    public String name() {
    return "Coke";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Pepsi extends ColdDrink {
    @Override
    public float price() {
    return 35.0f;
    }
    @Override
    public String name() {
    return "Pepsi";
    }
    }

    下面是要建造者需要返回的装配完的对象:套餐
    套餐对象本身定义好了自由的装配方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import java.util.ArrayList;
    import java.util.List;
    public class Meal {
    private List<Item> items = new ArrayList<Item>();
    public void addItem(Item item){
    items.add(item);
    }
    public float getCost(){
    float cost = 0.0f;
    for (Item item : items) {
    cost += item.price();
    }
    return cost;
    }
    public void showItems(){
    for (Item item : items) {
    System.out.print("Item : "+item.name());
    System.out.print(", Packing : "+item.packing().pack());
    System.out.println(", Price : "+item.price());
    }
    }
    }

    下面是*建造者*(主要)
    这里的建造者已经固定了建造的方法,
    不过以后还可以扩展

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class MealBuilder {
    public Meal prepareVegMeal (){
    Meal meal = new Meal();
    meal.addItem(new VegBurger());
    meal.addItem(new Coke());
    return meal;
    }
    public Meal prepareNonVegMeal (){
    Meal meal = new Meal();
    meal.addItem(new ChickenBurger());
    meal.addItem(new Pepsi());
    return meal;
    }
    }

    使用的例子

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class BuilderPatternDemo {
    public static void main(String[] args) {
    MealBuilder mealBuilder = new MealBuilder();
    Meal vegMeal = mealBuilder.prepareVegMeal();
    System.out.println("Veg Meal");
    vegMeal.showItems();
    System.out.println("Total Cost: " +vegMeal.getCost());
    Meal nonVegMeal = mealBuilder.prepareNonVegMeal();
    System.out.println("\n\nNon-Veg Meal");
    nonVegMeal.showItems();
    System.out.println("Total Cost: " +nonVegMeal.getCost());
    }
    }

原型模式

  1. 概括

    使用new创建类非常繁琐或开销很大时(比如需要有权限,需要数据准备等)
    不新建而是拷贝一个新的对象返回

  2. 优点

    性能提高

  3. 缺点

    必须实现Cloneable接口,别人写的类不容易拷贝

  4. 使用场景

    性能优化

  5. 举例

    给Shape抽象类定义好克隆的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public abstract class Shape implements Cloneable {
    private String id;
    protected String type;
    abstract void draw();
    public String getType(){
    return type;
    }
    public String getId() {
    return id;
    }
    public void setId(String id) {
    this.id = id;
    }
    public Object clone() {
    Object clone = null;
    try {
    clone = super.clone();
    } catch (CloneNotSupportedException e) {
    e.printStackTrace();
    }
    return clone;
    }
    }

    目的是为了以下三个实体类有克隆的能力

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Rectangle extends Shape {
    public Rectangle(){
    type = "Rectangle";
    }
    @Override
    public void draw() {
    System.out.println("Inside Rectangle::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Square extends Shape {
    public Square(){
    type = "Square";
    }
    @Override
    public void draw() {
    System.out.println("Inside Square::draw() method.");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Circle extends Shape {
    public Circle(){
    type = "Circle";
    }
    @Override
    public void draw() {
    System.out.println("Inside Circle::draw() method.");
    }
    }

    创建一个有Cache的*原型克隆机*(主要)
    getShape方法中使用id请求一个与该id相同的类的克隆对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import java.util.Hashtable;
    public class ShapeCache {
    private static Hashtable<String, Shape> shapeMap = new Hashtable<String, Shape>();
    public static Shape getShape(String shapeId) {
    Shape cachedShape = shapeMap.get(shapeId);
    return (Shape) cachedShape.clone();
    }
    // 对每种形状都运行数据库查询,并创建该形状
    // shapeMap.put(shapeKey, shape);
    // 例如,我们要添加三种形状
    public static void loadCache() {
    Circle circle = new Circle(); // 假设这个很耗费资源
    circle.setId("1");
    shapeMap.put(circle.getId(),circle);
    Square square = new Square();
    square.setId("2");
    shapeMap.put(square.getId(),square);
    Rectangle rectangle = new Rectangle();
    rectangle.setId("3");
    shapeMap.put(rectangle.getId(),rectangle);
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class PrototypePatternDemo {
    public static void main(String[] args) {
    ShapeCache.loadCache();
    Shape clonedShape = (Shape) ShapeCache.getShape("1");
    System.out.println("Shape : " + clonedShape.getType());
    Shape clonedShape2 = (Shape) ShapeCache.getShape("2");
    System.out.println("Shape : " + clonedShape2.getType());
    Shape clonedShape3 = (Shape) ShapeCache.getShape("3");
    System.out.println("Shape : " + clonedShape3.getType());
    }
    }

结构型模式

关注的是类和对象的组合方法.关注通用性和系统更改时的代价

适配器模式

  1. 概括

    在已经运行的系统中,将一个类的接口转换成另一个接口
    使用旧接口的情况:
    ​ 一个类使用旧接口
    ​ 该类的内部使用新的接口的类的对象来实现功能

  2. 优点

    提高了类的复用能力,灵活性好

  3. 缺点

    使用太多不利于把握项目结构

  4. 使用场景

    有动机地修改一个正常运行的系统的接口

  5. 举例

    旧接口: 只能播放MP3

    1
    2
    3
    public interface MediaPlayer {
    public void play(String audioType, String fileName);
    }

    新接口及其实现类
    能播放mp4及vlc

    1
    2
    3
    4
    public interface AdvancedMediaPlayer { 
    public void playVlc(String fileName);
    public void playMp4(String fileName);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class VlcPlayer implements AdvancedMediaPlayer{
    @Override
    public void playVlc(String fileName) {
    System.out.println("Playing vlc file. Name: "+ fileName);
    }
    @Override
    public void playMp4(String fileName) {
    //什么也不做
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Mp4Player implements AdvancedMediaPlayer{
    @Override
    public void playVlc(String fileName) {
    //什么也不做
    }
    @Override
    public void playMp4(String fileName) {
    System.out.println("Playing mp4 file. Name: "+ fileName);
    }
    }

    *适配器类*(主要)
    外部使用旧接口
    内部使用新接口的实现类(具有新接口的方法)执行功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class MediaAdapter implements MediaPlayer {
    AdvancedMediaPlayer advancedMusicPlayer; // 接口名可以作为类型名
    public MediaAdapter(String audioType){ // 接
    if(audioType.equalsIgnoreCase("vlc") ){
    advancedMusicPlayer = new VlcPlayer();
    } else if (audioType.equalsIgnoreCase("mp4")){
    advancedMusicPlayer = new Mp4Player();
    }
    }
    @Override
    public void play(String audioType, String fileName) {
    if(audioType.equalsIgnoreCase("vlc")){
    advancedMusicPlayer.playVlc(fileName);
    }else if(audioType.equalsIgnoreCase("mp4")){
    advancedMusicPlayer.playMp4(fileName);
    }
    }
    }

    两次实现类对比
    对外接口不变,但内部使用了适配器接口的类,使用该类来完成功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class AudioPlayer implements MediaPlayer {
    MediaAdapter mediaAdapter;
    @Override
    public void play(String audioType, String fileName) {
    //播放 mp3 音乐文件的内置支持,println想象为原有功能
    if(audioType.equalsIgnoreCase("mp3")){
    System.out.println("Playing mp3 file. Name: "+ fileName);
    }
    + //mediaAdapter 提供了播放其他文件格式的支持
    + else if(audioType.equalsIgnoreCase("vlc")
    + || audioType.equalsIgnoreCase("mp4")){
    + mediaAdapter = new MediaAdapter(audioType);
    + mediaAdapter.play(audioType, fileName);
    + }
    else{
    System.out.println("Invalid media. "+
    audioType + " format not supported");
    }
    }
    }

    使用
    AudioPlayer也可以看做原有的类名,只不过其对象可以支持更多的格式了

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class AdapterPatternDemo {
    public static void main(String[] args) {
    AudioPlayer audioPlayer = new AudioPlayer();
    audioPlayer.play("mp3", "beyond the horizon.mp3");
    audioPlayer.play("mp4", "alone.mp4");
    audioPlayer.play("vlc", "far far away.vlc");
    audioPlayer.play("avi", "mind me.avi");
    }
    }

桥接模式

  1. 概括

    调用者使用接口调用被调用者,被调用者统一接口即可
    免去了调用者继承被调用者带来的过于庞大且不易扩展的问题

  2. 优点

    抽象和实现分离,扩展容易

  3. 缺点

    需要提前设计抽象层,较为难以理解

  4. 使用场景

    一个类存在两个独立变化的维度等

  5. 举例

    提前设计的接口

    1
    2
    3
    public interface DrawAPI {
    public void drawCircle(int radius, int x, int y);
    }

    被调用的类

    1
    2
    3
    4
    5
    6
    7
    public class RedCircle implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
    System.out.println("Drawing Circle[ color: red, radius: "
    + radius +", x: " +x+", "+ y +"]");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    public class GreenCircle implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
    System.out.println("Drawing Circle[ color: green, radius: "
    + radius +", x: " +x+", "+ y +"]");
    }
    }

    调用者,原本是需要继承被调用的类以实现其功能的,现在不用了,
    设立使用抽象类以实现调者这本身也可以独立发展

    1
    2
    3
    4
    5
    6
    7
    public abstract class Shape {
    protected DrawAPI drawAPI;
    protected Shape(DrawAPI drawAPI){
    this.drawAPI = drawAPI;
    }
    public abstract void draw();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Circle extends Shape {
    private int x, y, radius;
    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
    super(drawAPI);
    this.x = x;
    this.y = y;
    this.radius = radius;
    }
    public void draw() {
    drawAPI.drawCircle(radius,x,y);
    }
    }

    完成功能

    1
    2
    3
    4
    5
    6
    7
    8
    public class BridgePatternDemo {
    public static void main(String[] args) {
    Shape redCircle = new Circle(100,100, 10, new RedCircle());
    Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
    redCircle.draw();
    greenCircle.draw();
    }
    }

过滤器模式

  1. 概括

    又称为标准(名词)模式
    通过建立一系列的过滤器(各自有各自的过滤原则)
    以及一些用于逻辑运算工具,(只是抽象的,还不像简单过滤器一样拥有具体过滤功能,不过和简单过滤器搭配后就具有了具体过滤功能)
    然后真的用于过滤

  2. 优点

  3. 缺点

  4. 使用场景

    需要过滤出结果时候

  5. 举例

    被过滤的对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class Person {
    private String name;
    private String gender;
    private String maritalStatus;
    public Person(String name,String gender,String maritalStatus){
    this.name = name;
    this.gender = gender;
    this.maritalStatus = maritalStatus;
    }
    public String getName() {
    return name;
    }
    public String getGender() {
    return gender;
    }
    public String getMaritalStatus() {
    return maritalStatus;
    }
    }

    约定一个过滤时使用的接口
    接收列表返回过滤后的列表

    1
    2
    3
    4
    import java.util.List;
    public interface Criteria {
    public List<Person> meetCriteria(List<Person> persons);
    }

    简单过滤类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.ArrayList;
    import java.util.List;
    public class CriteriaMale implements Criteria {
    @Override
    public List<Person> meetCriteria(List<Person> persons) {
    List<Person> malePersons = new ArrayList<Person>();
    for (Person person : persons) {
    if(person.getGender().equalsIgnoreCase("MALE")){
    malePersons.add(person);
    }
    }
    return malePersons;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.ArrayList;
    import java.util.List;
    public class CriteriaFemale implements Criteria {
    @Override
    public List<Person> meetCriteria(List<Person> persons) {
    List<Person> femalePersons = new ArrayList<Person>();
    for (Person person : persons) {
    if(person.getGender().equalsIgnoreCase("FEMALE")){
    femalePersons.add(person);
    }
    }
    return femalePersons;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.ArrayList;
    import java.util.List;
    public class CriteriaSingle implements Criteria {
    @Override
    public List<Person> meetCriteria(List<Person> persons) {
    List<Person> singlePersons = new ArrayList<Person>();
    for (Person person : persons) {
    if(person.getMaritalStatus().equalsIgnoreCase("SINGLE")){
    singlePersons.add(person);
    }
    }
    return singlePersons;
    }
    }

    抽象过滤器,逻辑运算工具

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    import java.util.List;
    public class AndCriteria implements Criteria {
    private Criteria criteria;
    private Criteria otherCriteria;
    public AndCriteria(Criteria criteria, Criteria otherCriteria) {
    this.criteria = criteria;
    this.otherCriteria = otherCriteria;
    }
    @Override
    public List<Person> meetCriteria(List<Person> persons) {
    List<Person> firstCriteriaPersons = criteria.meetCriteria(persons);
    return otherCriteria.meetCriteria(firstCriteriaPersons);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    import java.util.List;
    public class OrCriteria implements Criteria {
    private Criteria criteria;
    private Criteria otherCriteria;
    public OrCriteria(Criteria criteria, Criteria otherCriteria) {
    this.criteria = criteria;
    this.otherCriteria = otherCriteria;
    }
    @Override
    public List<Person> meetCriteria(List<Person> persons) {
    List<Person> firstCriteriaItems = criteria.meetCriteria(persons);
    List<Person> otherCriteriaItems = otherCriteria.meetCriteria(persons);
    for (Person person : otherCriteriaItems) {
    if(!firstCriteriaItems.contains(person)){
    firstCriteriaItems.add(person);
    }
    }
    return firstCriteriaItems;
    }
    }

    用例

    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
    import java.util.ArrayList; 
    import java.util.List;
    public class CriteriaPatternDemo {
    public static void main(String[] args) {
    List<Person> persons = new ArrayList<Person>();
    persons.add(new Person("Robert","Male", "Single"));
    persons.add(new Person("John","Male", "Married"));
    persons.add(new Person("Laura","Female", "Married"));
    persons.add(new Person("Diana","Female", "Single"));
    persons.add(new Person("Mike","Male", "Single"));
    persons.add(new Person("Bobby","Male", "Single"));
    Criteria male = new CriteriaMale();
    Criteria female = new CriteriaFemale();
    Criteria single = new CriteriaSingle();
    Criteria singleMale = new AndCriteria(single, male);
    Criteria singleOrFemale = new OrCriteria(single, female);
    System.out.println("Males: ");
    printPersons(male.meetCriteria(persons));
    System.out.println("\nFemales: ");
    printPersons(female.meetCriteria(persons));
    System.out.println("\nSingle Males: ");
    printPersons(singleMale.meetCriteria(persons));
    System.out.println("\nSingle Or Females: ");
    printPersons(singleOrFemale.meetCriteria(persons));
    }
    public static void printPersons(List<Person> persons){
    for (Person person : persons) {
    System.out.println("Person : [ Name : " + person.getName()
    +", Gender : " + person.getGender()
    +", Marital Status : " + person.getMaritalStatus()
    +" ]");
    }
    }
    }

组合模式

  1. 概括

    将相似对象做成俄罗斯套娃(多人版),统一对外接口一方便使用,像树一样
    如container总可以使用add添加新的container

  2. 优点

    使用方便

  3. 缺点

    下一级的叶子使用的是类而不是接口,违反倒置原则

  4. 使用场景

    想表示层次结构

  5. 举例

    一个节点
    注意内部包含了下一级别的分支的列表

    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
    <pre class="prettyprint">
    import java.util.ArrayList;
    import java.util.List;
    public class Employee {
    private String name;
    private String dept;
    private int salary;
    private List<Employee> subordinates;
    //构造函数
    public Employee(String name,String dept, int sal) {
    this.name = name;
    this.dept = dept;
    this.salary = sal;
    subordinates = new ArrayList<Employee>();
    }
    public void add(Employee e) {
    subordinates.add(e);
    }
    public void remove(Employee e) {
    subordinates.remove(e);
    }
    public List<Employee> getSubordinates(){
    return subordinates;
    }
    public String toString(){
    return ("Employee :[ Name : "+ name
    +", dept : "+ dept + ", salary :"
    + salary+" ]");
    }
    }

    使用方法
    既可以作为叶子创建,又可以使用方法添加下一级别的分支

    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 CompositePatternDemo {
    public static void main(String[] args) {
    Employee CEO = new Employee("John","CEO", 30000);
    Employee headSales = new Employee("Robert","Head Sales", 20000);
    Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
    Employee clerk1 = new Employee("Laura","Marketing", 10000);
    Employee clerk2 = new Employee("Bob","Marketing", 10000);
    Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
    Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
    CEO.add(headSales);
    CEO.add(headMarketing);
    headSales.add(salesExecutive1);
    headSales.add(salesExecutive2);
    headMarketing.add(clerk1);
    headMarketing.add(clerk2);
    //打印该组织的所有员工
    System.out.println(CEO);
    for (Employee headEmployee : CEO.getSubordinates()) {
    System.out.println(headEmployee);
    for (Employee employee : headEmployee.getSubordinates()) {
    System.out.println(employee);
    }
    }
    }
    }

装饰器模式

  1. 概括

    使用抽象类包装旧类,使用同样接口(比如接收参数后原样传递)
    然后使用装饰器类继承抽象类,不加入自身方法
    即使被装饰类发生变化(比如加入了必须初始化且public的成员,已经不方便使用继承来实现装饰功能),仍然可以正常使用

  2. 优点

    装饰类和被装饰类可以独立发展
    一定程度上可以代替继承

  3. 缺点

    多层装饰比较复杂

  4. 使用场景

    扩展一个现有类的功能

  5. 举例

    旧类及其使用的接口

    1
    2
    3
    public interface Shape {
    void draw();
    }
    1
    2
    3
    4
    5
    6
    public class Rectangle implements Shape {
    @Override
    public void draw() {
    System.out.println("Shape: Rectangle");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Circle implements Shape {
    @Override
    public void draw() {
    System.out.println("Shape: Circle");
    }
    }

    装饰用的抽象类
    注意依赖的是接口,这样可以装饰多个类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;
    public ShapeDecorator(Shape decoratedShape){
    this.decoratedShape = decoratedShape;
    }
    public void draw(){
    decoratedShape.draw();
    }
    }

    具体装饰效果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class RedShapeDecorator extends ShapeDecorator {
    public RedShapeDecorator(Shape decoratedShape) {
    super(decoratedShape);
    }
    @Override
    public void draw() {
    decoratedShape.draw();
    setRedBorder(decoratedShape);
    }
    private void setRedBorder(Shape decoratedShape){
    System.out.println("Border Color: Red");
    }
    }

    使用效果

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class DecoratorPatternDemo {
    public static void main(String[] args) {
    Shape circle = new Circle();
    Shape redCircle = new RedShapeDecorator(new Circle());
    Shape redRectangle = new RedShapeDecorator(new Rectangle());
    System.out.println("Circle with normal border");
    circle.draw();
    System.out.println("\nCircle of red border");
    redCircle.draw();
    System.out.println("\nRectangle of red border");
    redRectangle.draw();
    }
    }

外观模式

  1. 概括

    为现有系统建立一个类,一隐藏内部结构,简化使用或者防止傻瓜等

  2. 优点

    提高了灵活性,提高了安全性

  3. 缺点

    不符合开闭原则,改东西麻烦

  4. 使用场景

    为复杂系统提供外界访问模块

  5. 举例

    假想复杂系统
    复杂在说橙色draw方法时候需要先new对象,且根据要画的东西不同而需要new的对象不同

    1
    2
    3
    public interface Shape {
    void draw();
    }
    1
    2
    3
    4
    5
    6
    public class Rectangle implements Shape {
    @Override
    public void draw() {
    System.out.println("Rectangle::draw()");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Square implements Shape {
    @Override
    public void draw() {
    System.out.println("Square::draw()");
    }
    }
    1
    2
    3
    4
    5
    6
    public class Circle implements Shape {
    @Override
    public void draw() {
    System.out.println("Circle::draw()");
    }
    }

    外观类
    包含了复杂操作,提供一个较为简单的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class ShapeMaker {
    private Shape circle;
    private Shape rectangle;
    private Shape square;
    public ShapeMaker() {
    circle = new Circle();
    rectangle = new Rectangle();
    square = new Square();
    }
    public void drawCircle(){
    circle.draw();
    }
    public void drawRectangle(){
    rectangle.draw();
    }
    public void drawSquare(){
    square.draw();
    }
    }

    使用时只需要new一个对象,并且要画的东西直接和方法名相关

    1
    2
    3
    4
    5
    6
    7
    8
    public class FacadePatternDemo {
    public static void main(String[] args) {
    ShapeMaker shapeMaker = new ShapeMaker();
    shapeMaker.drawCircle();
    shapeMaker.drawRectangle();
    shapeMaker.drawSquare();
    }
    }

享元模式

  1. 概括

    借助一个标识以实现:
    若已经创建则返回已经创建的对象
    若未创建则新建一个并返回

  2. 优点

    减少内存占用

  3. 缺点

    这个标识不容易找到

  4. 使用场景

    系统中要大量相似对象,需要缓冲池,
    java中的string对象
    数据库的数据池

  5. 举例

    被创建的对象的接口及其类

    1
    2
    3
    public interface Shape {
    void draw();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class Circle implements Shape {
    private String color;
    private int x;
    private int y;
    private int radius;
    public Circle(String color){
    this.color = color;
    }
    public void setX(int x) {
    this.x = x;
    }
    public void setY(int y) {
    this.y = y;
    }
    public void setRadius(int radius) {
    this.radius = radius;
    }
    @Override
    public void draw() {
    System.out.println("Circle: Draw() [Color : " + color
    +", x : " + x +", y :" + y +", radius :" + radius);
    }
    }

    完成池的功能

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import java.util.HashMap;
    public class ShapeFactory {
    private static final HashMap<String, Shape> circleMap = new HashMap<>();
    public static Shape getCircle(String color) {
    Circle circle = (Circle)circleMap.get(color);
    if(circle == null) {
    circle = new Circle(color);
    circleMap.put(color, circle);
    System.out.println("Creating circle of color : " + color);
    }
    return circle;
    }
    }

    使用,这里使用颜色作为唯一性的标识

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class FlyweightPatternDemo {
    private static final String colors[] =
    { "Red", "Green", "Blue", "White", "Black" };
    public static void main(String[] args) {
    for(int i=0; i < 20; ++i) {
    Circle circle =
    (Circle)ShapeFactory.getCircle(getRandomColor());
    circle.setX(getRandomX());
    circle.setY(getRandomY());
    circle.setRadius(100);
    circle.draw();
    }
    }
    private static String getRandomColor() {
    return colors[(int)(Math.random()*colors.length)];
    }
    private static int getRandomX() {
    return (int)(Math.random()*100 );
    }
    private static int getRandomY() {
    return (int)(Math.random()*100);
    }
    }

代理模式

  1. 概括

    增加一个代理以实现一些目的(减少开销,安全问题)
    与被代理类使用同样的接口,并在内部初始化被代理类一完成对其的控制

  2. 优点

    职责清晰,容易扩展

  3. 缺点

    可能造成请求处理缓慢

  4. 使用场景

    远程代理
    虚拟代理
    Copy-on-Write代理
    保护代理
    Cache代理
    防火墙代理
    同步化代理
    智能引用代理

  5. 举例

    这里为了减少系统开销(初始化时间)
    共同的接口

    1
    2
    3
    public interface Image {
    void display();
    }

    被代理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class RealImage implements Image {
    private String fileName;
    public RealImage(String fileName){
    this.fileName = fileName;
    loadFromDisk(fileName);
    }
    @Override
    public void display() {
    System.out.println("Displaying " + fileName);
    }
    // 假设这里很消耗资源
    private void loadFromDisk(String fileName){
    System.out.println("Loading " + fileName);
    }
    }

    代理类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class ProxyImage implements Image{
    private RealImage realImage;
    private String fileName;
    public ProxyImage(String fileName){
    this.fileName = fileName;
    }
    // 使用了缓存
    @Override
    public void display() {
    if(realImage == null){
    realImage = new RealImage(fileName);
    }
    realImage.display();
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class ProxyPatternDemo {
    public static void main(String[] args) {
    Image image = new ProxyImage("test_10mb.jpg");
    // 图像将从磁盘加载
    image.display();
    System.out.println("");
    // 图像不需要从磁盘加载
    image.display();
    }
    }

行为型模式

关注对象之间的通信

责任链模式

  1. 概括

    使请求的发送者和接受者分开,以往可能会在发送者的方法中调用接收者的方法
    事先约定一个接收者的接口,同时在每个接收者中都指向下一个环节,形成一个隐形的链

  2. 优点

    发送者无需了解链的结构

  3. 缺点

    请求不一定被处理(尤其是当链并不是一条,结构复杂时)

  4. 使用场景

    多个对象处理请求,当不确定什么时候处理,也不明白一个请求具体是谁处理

  5. 举例

    请求的(接口)抽象类,
    同时兼具构造请求链的功能(使用setNextLogger方法)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public abstract class AbstractLogger {
    public static int INFO = 1;
    public static int DEBUG = 2;
    public static int ERROR = 3;
    protected int level;
    //责任链中的下一个元素
    protected AbstractLogger nextLogger;
    public void setNextLogger(AbstractLogger nextLogger){
    this.nextLogger = nextLogger;
    }
    public void logMessage(int level, String message){
    if(this.level <= level){
    write(message);
    }
    if(nextLogger !=null){
    nextLogger.logMessage(level, message);
    }
    }
    abstract protected void write(String message);
    }

    三个具体的处理器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class ConsoleLogger extends AbstractLogger {
    public ConsoleLogger(int level){
    this.level = level;
    }
    @Override
    protected void write(String message) {
    System.out.println("Standard Console::Logger: " + message);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class ErrorLogger extends AbstractLogger {
    public ErrorLogger(int level){
    this.level = level;
    }
    @Override
    protected void write(String message) {
    System.out.println("Error Console::Logger: " + message);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class FileLogger extends AbstractLogger {
    public FileLogger(int level){
    this.level = level;
    }
    @Override
    protected void write(String message) {
    System.out.println("File::Logger: " + message);
    }
    }

    具体使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class ChainPatternDemo {
    private static AbstractLogger getChainOfLoggers(){
    AbstractLogger errorLogger = new ErrorLogger(AbstractLogger.ERROR);
    AbstractLogger fileLogger = new FileLogger(AbstractLogger.DEBUG);
    AbstractLogger consoleLogger = new ConsoleLogger(AbstractLogger.INFO);
    errorLogger.setNextLogger(fileLogger);
    fileLogger.setNextLogger(consoleLogger);
    return errorLogger;
    }
    public static void main(String[] args) {
    // 这里使用一条可见的责任链
    AbstractLogger loggerChain = getChainOfLoggers();
    loggerChain.logMessage(AbstractLogger.INFO,
    "This is an information.");
    loggerChain.logMessage(AbstractLogger.DEBUG,
    "This is an debug level information.");
    // 发送者并不需要指定是哪个logger
    loggerChain.logMessage(AbstractLogger.ERROR,
    "This is an error information.");
    }
    }

命令模式

  1. 概括

    解耦请求与处理的另一种方式
    请求者–>invoker(调用者)–>执行者
    将请求封装成了对象

  2. 优点

    降低系统耦合度
    容易扩展

  3. 缺点

    可能导致命令类过多

  4. 使用场景

    认为是命令的地方均可

  5. 举例

    命令的接口与实体类

    1
    2
    3
    public interface Order {
    void execute();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class BuyStock implements Order {
    private Stock abcStock;
    public BuyStock(Stock abcStock){
    this.abcStock = abcStock;
    }
    public void execute() {
    abcStock.buy();
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class SellStock implements Order {
    private Stock abcStock;
    public SellStock(Stock abcStock){
    this.abcStock = abcStock;
    }
    public void execute() {
    abcStock.sell();
    }
    }

    其中stock类是具体的命令内容
    这里的请求内容还可以定制

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Stock {
    private String name = "ABC";
    private int quantity = 10;
    public void buy(){
    System.out.println("Stock [ Name: "+name+",
    Quantity: " + quantity +" ] bought");
    }
    public void sell(){
    System.out.println("Stock [ Name: "+name+",
    Quantity: " + quantity +" ] sold");
    }
    }

    具体的控制器类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    import java.util.ArrayList;
    import java.util.List;
    // 本身有命令列表
    public class Broker {
    private List<Order> orderList = new ArrayList<Order>();
    // 也有添加列表内容的命令
    public void takeOrder(Order order){
    orderList.add(order);
    }
    // 控制命令执行的部分
    public void placeOrders(){
    for (Order order : orderList) {
    order.execute();
    }
    orderList.clear();
    }
    }

    使用例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class CommandPatternDemo {
    public static void main(String[] args) {
    Stock abcStock = new Stock();
    BuyStock buyStockOrder = new BuyStock(abcStock);
    SellStock sellStockOrder = new SellStock(abcStock);
    Broker broker = new Broker();
    broker.takeOrder(buyStockOrder);
    broker.takeOrder(sellStockOrder);
    broker.placeOrders();
    }
    }

解释器模式

  1. 概括

    对一个语法,构造解释器以解释语言中句子

  2. 优点

    容易扩展

  3. 缺点

    可使用场景比较少,复杂语法不容易构建解释器

  4. 使用场景

    SQL解析等

  5. 举例

    想象一种语言,表达式本身非true即false
    有原子句与复杂句
    下面是接口

    1
    2
    3
    public interface Expression {
    public boolean interpret(String context);
    }

    原子句的语法: 包含某字(用户设置)则为真

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class TerminalExpression implements Expression {
    private String data;
    public TerminalExpression(String data){
    this.data = data;
    }
    @Override
    public boolean interpret(String context) {
    if(context.contains(data)){
    return true;
    }
    return false;
    }
    }

    用于逻辑运算的语法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class OrExpression implements Expression {
    private Expression expr1 = null;
    private Expression expr2 = null;
    public OrExpression(Expression expr1, Expression expr2) {
    this.expr1 = expr1;
    this.expr2 = expr2;
    }
    @Override
    public boolean interpret(String context) {
    return expr1.interpret(context) || expr2.interpret(context);
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class AndExpression implements Expression {
    private Expression expr1 = null;
    private Expression expr2 = null;
    public AndExpression(Expression expr1, Expression expr2) {
    this.expr1 = expr1;
    this.expr2 = expr2;
    }
    @Override
    public boolean interpret(String context) {
    return expr1.interpret(context) && expr2.interpret(context);
    }
    }

    使用
    具体的规则是在使用时候定义的

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class InterpreterPatternDemo {
    //规则:Robert 和 John 是男性
    public static Expression getMaleExpression(){
    Expression robert = new TerminalExpression("Robert");
    Expression john = new TerminalExpression("John");
    return new OrExpression(robert, john);
    }
    //规则:Julie 是一个已婚的女性
    public static Expression getMarriedWomanExpression(){
    Expression julie = new TerminalExpression("Julie");
    Expression married = new TerminalExpression("Married");
    return new AndExpression(julie, married);
    }
    public static void main(String[] args) {
    Expression isMale = getMaleExpression();
    Expression isMarriedWoman = getMarriedWomanExpression();
    System.out.println("John is male? " + isMale.interpret("John"));
    System.out.println("Julie is a married women? "
    + isMarriedWoman.interpret("Married Julie"));
    }
    }

迭代器模式

  1. 概括

    为不同的数据结构提供一种统一的,简单的对外接口(如next与hasNext)
    防止数据泄露或用户不明白使用方法

  2. 优点

    使用方便

  3. 缺点

    增加新的数据结构时需要增加迭代器类,导致类过多

  4. 使用场景

    用户要这个需要的时候

  5. 举例

    先约定一个获得迭代器的方法,同时根据这种方法来做数据的主体

    1
    2
    3
    public interface Container {
    public Iterator getIterator();
    }

    再约定一个迭代器本身的接口

    1
    2
    3
    4
    public interface Iterator {
    public boolean hasNext();
    public Object next();
    }

    一个制作迭代类的例子
    这里使用的是内部类,但不妨碍能看出,一种数据结构就需要一种迭代器类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class NameRepository implements Container {
    public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
    @Override
    public Iterator getIterator() {
    return new NameIterator();
    }
    private class NameIterator implements Iterator {
    int index;
    @Override
    public boolean hasNext() {
    if(index < names.length){
    return true;
    }
    return false;
    }
    @Override
    public Object next() {
    if(this.hasNext()){
    return names[index++];
    }
    return null;
    }
    }
    }

    使用者角度看很简单

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class IteratorPatternDemo {
    public static void main(String[] args) {
    NameRepository namesRepository = new NameRepository();
    for(Iterator iter = namesRepository.getIterator(); iter.hasNext();){
    String name = (String)iter.next();
    System.out.println("Name : " + name);
    }
    }
    }

中介者模式

  1. 概括

    使用中介对象封装对象间通信,降低对象间通信的复杂性

  2. 优点

    符合迪米特原则

  3. 缺点

    终结者会庞大,变得复杂

  4. 使用场景

    对象间有复杂的引用关系

  5. 举例

    类间通信的主体
    从方法看出是发送信息到中介

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class User {
    private String name;
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public User(String name){
    this.name = name;
    }
    public void sendMessage(String message){
    ChatRoom.showMessage(this,message);
    }
    }

    中介

    1
    2
    3
    4
    5
    6
    7
    import java.util.Date;
    public class ChatRoom {
    public static void showMessage(User user, String message){
    System.out.println(new Date().toString()
    + " [" + user.getName() +"] : " + message);
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    public class MediatorPatternDemo {
    public static void main(String[] args) {
    User robert = new User("Robert");
    User john = new User("John");
    robert.sendMessage("Hi! John!");
    john.sendMessage("Hello! Robert!");
    }
    }

备忘录模式

  1. 概括

    用于保存对象信息,在适当时候恢复对象.

  2. 做法

    定义备忘对象,数据对象,数据管理者对象

  3. 优点

    实现了信息的封装,不用关心保存时的细节(哪些需要保存,哪些不需要)

  4. 缺点

    消耗资源

  5. 使用场景

    需要保存,恢复数据时

  6. 举例

    数据对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Memento {
    private String state;
    public Memento(String state){
    this.state = state;
    }
    public String getState(){
    return state;
    }
    }

    被备份对象
    可以具有用于保存数据的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class Originator {
    private String state;
    public void setState(String state){
    this.state = state;
    }
    public String getState(){
    return state;
    }
    // 保存数据的方法
    public Memento saveStateToMemento(){
    return new Memento(state);
    }
    // 恢复数据的方法
    public void getStateFromMemento(Memento Memento){
    state = Memento.getState();
    }
    }

    数据管理中心

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import java.util.ArrayList;
    import java.util.List;
    public class CareTaker {
    private List<Memento> mementoList = new ArrayList<Memento>();
    // 添加数据
    public void add(Memento state){
    mementoList.add(state);
    }
    // 取出数据
    public Memento get(int index){
    return mementoList.get(index);
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class MementoPatternDemo {
    public static void main(String[] args) {
    Originator originator = new Originator();
    CareTaker careTaker = new CareTaker();
    originator.setState("State #1");
    originator.setState("State #2");
    careTaker.add(originator.saveStateToMemento());
    originator.setState("State #3");
    careTaker.add(originator.saveStateToMemento());
    originator.setState("State #4");
    System.out.println("Current State: " + originator.getState());
    originator.getStateFromMemento(careTaker.get(0));
    System.out.println("First saved State: " + originator.getState());
    originator.getStateFromMemento(careTaker.get(1));
    System.out.println("Second saved State: " + originator.getState());
    }
    }

观察者模式

  1. 概括

    对象间存在一对多关系时,可以使用观察者模式
    当一个对象状态改变时,通知所有的观察者
    在被观察者的抽象类内部建立一个列表保存所有的观察者,在被观察者发生变化后,向列表中的所有元素发出通知(比如调用观察者的方法)

  2. 优点

    使用的是抽象的耦合方法

  3. 缺点

    观察者和被观察者之间有循环依赖接乱了

  4. 使用场景

    一个对象改变后需要另一些对象也改变

  5. 举例

    被观察者类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    import java.util.ArrayList;
    import java.util.List;
    public class Subject {
    private List<Observer> observers
    = new ArrayList<Observer>();
    private int state;
    public int getState() {
    return state;
    }
    public void setState(int state) {
    this.state = state;
    notifyAllObservers();
    }
    public void attach(Observer observer){
    observers.add(observer);
    }
    public void notifyAllObservers(){
    for (Observer observer : observers) {
    observer.update();
    }
    }
    }

    观察者类的抽象类和实体类

    1
    2
    3
    4
    public abstract class Observer {
    protected Subject subject;
    public abstract void update();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class BinaryObserver extends Observer{
    public BinaryObserver(Subject subject){
    this.subject = subject;
    this.subject.attach(this);
    }
    @Override
    public void update() {
    System.out.println( "Binary String: "
    + Integer.toBinaryString( subject.getState() ) );
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class OctalObserver extends Observer{
    public OctalObserver(Subject subject){
    this.subject = subject;
    this.subject.attach(this);
    }
    @Override
    public void update() {
    System.out.println( "Octal String: "
    + Integer.toOctalString( subject.getState() ) );
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class HexaObserver extends Observer{
    public HexaObserver(Subject subject){
    this.subject = subject;
    this.subject.attach(this);
    }
    @Override
    public void update() {
    System.out.println( "Hex String: "
    + Integer.toHexString( subject.getState() ).toUpperCase() );
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class ObserverPatternDemo {
    public static void main(String[] args) {
    Subject subject = new Subject();
    new HexaObserver(subject);
    new OctalObserver(subject);
    new BinaryObserver(subject);
    System.out.println("First state change: 15");
    subject.setState(15);
    System.out.println("Second state change: 10");
    subject.setState(10);
    }
    }

状态模式

  1. 概括

    不使用if…else来根据状态采取行动,
    而是将状态封装为类,在表示状态的类中封装如该状态下的行动
    然后在主体中切换状态为该状态

  2. 优点

    减少了if…else的使用,易于理解

  3. 缺点

    需要增加新的类

  4. 使用场景

    用于替代if…else语句的部分使用场景

  5. 举例

    状态的接口与实体类

    1
    2
    3
    public interface State {
    public void doAction(Context context);
    }

    注意实体类中提供toString方法用于显示目前的状态,而doAction则为该状态下的行为

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class StartState implements State {
    public void doAction(Context context) {
    System.out.println("Player is in start state");
    context.setState(this);
    }
    public String toString(){
    return "Start State";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class StopState implements State {
    public void doAction(Context context) {
    System.out.println("Player is in stop state");
    context.setState(this);
    }
    public String toString(){
    return "Stop State";
    }
    }

    需要切换状态的主体
    使用抽象依赖,保证可以切换不同的状态

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class Context {
    private State state;
    public Context(){
    state = null;
    }
    public void setState(State state){
    this.state = state;
    }
    public State getState(){
    return state;
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class StatePatternDemo {
    public static void main(String[] args) {
    Context context = new Context();
    StartState startState = new StartState();
    startState.doAction(context);
    System.out.println(context.getState().toString());
    StopState stopState = new StopState();
    stopState.doAction(context);
    System.out.println(context.getState().toString());
    }
    }

空对象模式

  1. 概括

    有时要求函数返回一个空对象(即对象的方法皆可使用,仅仅是方法的输出结果为默认的无意义结果),而不是null
    方法:顶层建立一个抽象类,非空对象给予有实际意义的方法,空对象给予默认的方法

  2. 优点

  3. 缺点

  4. 使用场景

  5. 举例

    非空对象和空对象之母

    1
    2
    3
    4
    5
    public abstract class AbstractCustomer {
    protected String name;
    public abstract boolean isNil();
    public abstract String getName();
    }

    非空对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class RealCustomer extends AbstractCustomer {
    public RealCustomer(String name) {
    this.name = name;
    }
    @Override
    public String getName() {
    return name;
    }
    @Override
    public boolean isNil() {
    return false;
    }
    }

    空对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class NullCustomer extends AbstractCustomer {
    @Override
    public String getName() {
    return "Not Available in Customer Database";
    }
    @Override
    public boolean isNil() {
    return true;
    }
    }

    使用一个工厂类,也解释开头需要返回空对象而不是null的类
    这里暴力规定在名单中就返回非空对象,不在名单中就返回默认的空对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class CustomerFactory {
    public static final String[] names = {"Rob", "Joe", "Julie"};
    public static AbstractCustomer getCustomer(String name){
    for (int i = 0; i < names.length; i++) {
    if (names[i].equalsIgnoreCase(name)){
    return new RealCustomer(name);
    }
    }
    return new NullCustomer();
    }
    }

    具体使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class NullPatternDemo {
    public static void main(String[] args) {
    AbstractCustomer customer1 = CustomerFactory.getCustomer("Rob");
    AbstractCustomer customer2 = CustomerFactory.getCustomer("Bob");
    AbstractCustomer customer3 = CustomerFactory.getCustomer("Julie");
    AbstractCustomer customer4 = CustomerFactory.getCustomer("Laura");
    System.out.println("Customers");
    System.out.println(customer1.getName());
    System.out.println(customer2.getName());
    System.out.println(customer3.getName());
    System.out.println(customer4.getName());
    }
    }

策略模式

  1. 概括

    基本同状态模式

  2. 优点

    避免使用if时容易出错的现象,容易扩展

  3. 缺点

    类会增多,类会暴露

  4. 使用场景

  5. 举例

    策略类的接口及其实体类

    1
    2
    3
    public interface Strategy {
    public int doOperation(int num1, int num2);
    }
    1
    2
    3
    4
    5
    6
    public class OperationAdd implements Strategy{
    @Override
    public int doOperation(int num1, int num2) {
    return num1 + num2;
    }
    }
    1
    2
    3
    4
    5
    6
    public class OperationSubstract implements Strategy{
    @Override
    public int doOperation(int num1, int num2) {
    return num1 - num2;
    }
    }
    1
    2
    3
    4
    5
    6
    public class OperationMultiply implements Strategy{
    @Override
    public int doOperation(int num1, int num2) {
    return num1 * num2;
    }
    }

    需要选择策略的类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Context {
    private Strategy strategy;
    public Context(Strategy strategy){
    this.strategy = strategy;
    }
    public int executeStrategy(int num1, int num2){
    return strategy.doOperation(num1, num2);
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class StrategyPatternDemo {
    public static void main(String[] args) {
    Context context = new Context(new OperationAdd());
    System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
    context = new Context(new OperationSubstract());
    System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
    context = new Context(new OperationMultiply());
    System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
    }
    }

模板模式

  1. 概括

    大框架的流程定好(抽象类中),小问题的处理方延迟解决(抽象类的子类,实体类中)

  2. 优点

    便于维护,大方向不出错

  3. 缺点

    子类个数增加

  4. 使用场景

    大同小异的情况

  5. 举例

    定义了大方向的抽象类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public abstract class Game {
    abstract void initialize();
    abstract void startPlay();
    abstract void endPlay();
    //模板
    public final void play(){
    //初始化游戏
    initialize();
    //开始游戏
    startPlay();
    //结束游戏
    endPlay();
    }
    }

    具体问题具体处理的子类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Cricket extends Game {
    @Override
    void endPlay() {
    System.out.println("Cricket Game Finished!");
    }
    @Override
    void initialize() {
    System.out.println("Cricket Game Initialized! Start playing.");
    }
    @Override
    void startPlay() {
    System.out.println("Cricket Game Started. Enjoy the game!");
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class Football extends Game {
    @Override
    void endPlay() {
    System.out.println("Football Game Finished!");
    }
    @Override
    void initialize() {
    System.out.println("Football Game Initialized! Start playing.");
    }
    @Override
    void startPlay() {
    System.out.println("Football Game Started. Enjoy the game!");
    }
    }

    使用方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class TemplatePatternDemo {
    public static void main(String[] args) {
    Game game = new Cricket();
    game.play();
    System.out.println();
    game = new Football();
    game.play();
    }
    }

访问者模式

  1. 概括

    使用访问者体统方法,使用接待者提供数据

  2. 优点

    符合单一职责的原则,容易扩展,灵活

  3. 缺点

    具体数据对访问者公布细节,违反迪米特原则
    违反了倒置依赖原则

  4. 使用场景

    稳定的数据结构和多变的操作

  5. 举例

    数据结构的接口及其实体类
    其中还定义了用于接待访客的方法,等于是传输数据的方法

    1
    2
    3
    public interface ComputerPart {
    public void accept(ComputerPartVisitor computerPartVisitor);
    }
    1
    2
    3
    4
    5
    6
    public class Keyboard  implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
    1
    2
    3
    4
    5
    6
    public class Monitor  implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }
    1
    2
    3
    4
    5
    6
    public class Mouse  implements ComputerPart {
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    computerPartVisitor.visit(this);
    }
    }

    容纳数据结构的类,但为了也有自己的访问者,也使用了同样的接口

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class Computer implements ComputerPart {
    ComputerPart[] parts;
    public Computer(){
    parts = new ComputerPart[] {new Mouse(), new Keyboard(), new Monitor()};
    }
    @Override
    public void accept(ComputerPartVisitor computerPartVisitor) {
    for (int i = 0; i < parts.length; i++) {
    parts[i].accept(computerPartVisitor);
    }
    computerPartVisitor.visit(this);
    }
    }

    访问者的接口及其实体类

    1
    2
    3
    4
    5
    6
    public interface ComputerPartVisitor {
    public void visit(Computer computer);
    public void visit(Mouse mouse);
    public void visit(Keyboard keyboard);
    public void visit(Monitor monitor);
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class ComputerPartDisplayVisitor implements ComputerPartVisitor {
    @Override
    public void visit(Computer computer) {
    System.out.println("Displaying Computer.");
    }
    @Override
    public void visit(Mouse mouse) {
    System.out.println("Displaying Mouse.");
    }
    @Override
    public void visit(Keyboard keyboard) {
    System.out.println("Displaying Keyboard.");
    }
    @Override
    public void visit(Monitor monitor) {
    System.out.println("Displaying Monitor.");
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    public class VisitorPatternDemo {
    public static void main(String[] args) {
    ComputerPart computer = new Computer();
    computer.accept(new ComputerPartDisplayVisitor());
    }
    }

J2EE模式

关注表示层,由Sun Java Center鉴定

MVC模式

  1. 概括

    controller中引用model于view对象,controller完成对model的更新后调用view显示model的状态

  2. 优点

    职责清晰

  3. 缺点

  4. 使用场景

    许多web应用中

  5. 举例

    model

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class Student {
    private String rollNo;
    private String name;
    public String getRollNo() {
    return rollNo;
    }
    public void setRollNo(String rollNo) {
    this.rollNo = rollNo;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    }

    view

    1
    2
    3
    4
    5
    6
    7
    public class StudentView {
    public void printStudentDetails(String studentName, String studentRollNo){
    System.out.println("Student: ");
    System.out.println("Name: " + studentName);
    System.out.println("Roll No: " + studentRollNo);
    }
    }

    controller
    注意其中的model和view成员

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    public class StudentController {
    private Student model;
    private StudentView view;
    public StudentController(Student model, StudentView view){
    this.model = model;
    this.view = view;
    }
    public void setStudentName(String name){
    model.setName(name);
    }
    public String getStudentName(){
    return model.getName();
    }
    public void setStudentRollNo(String rollNo){
    model.setRollNo(rollNo);
    }
    public String getStudentRollNo(){
    return model.getRollNo();
    }
    public void updateView(){
    view.printStudentDetails(model.getName(), model.getRollNo());
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class MVCPatternDemo {
    public static void main(String[] args) {
    //从数据库获取学生记录
    Student model = retriveStudentFromDatabase();
    //创建一个视图:把学生详细信息输出到控制台
    StudentView view = new StudentView();
    StudentController controller = new StudentController(model, view);
    controller.updateView();
    //更新模型数据
    controller.setStudentName("John");
    controller.updateView();
    }
    private static Student retriveStudentFromDatabase(){
    Student student = new Student();
    student.setName("Robert");
    student.setRollNo("10");
    return student;
    }
    }

业务代表模式

  1. 概括

    客户需要某种服务,目前已经有查询服务(使用服务名查询业务服务),和具体执行动作的业务服务
    在添加一个业务代表,包办从使用服务名查询到给出结果的整个流程,
    客户仅仅提供服务名,然后开始等待即可

  2. 举例

    为了供查询服务使用,实际的业务服务有公共的接口

    1
    2
    3
    public interface BusinessService {
    public void doProcessing();
    }

    实体业务服务

    1
    2
    3
    4
    5
    6
    public class EJBService implements BusinessService {
    @Override
    public void doProcessing() {
    System.out.println("Processing task by invoking EJB Service");
    }
    }
    1
    2
    3
    4
    5
    6
    public class JMSService implements BusinessService {
    @Override
    public void doProcessing() {
    System.out.println("Processing task by invoking JMS Service");
    }
    }

    查询服务,注意返回值的类型使用的是接口名

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class BusinessLookUp {
    public BusinessService getBusinessService(String serviceType){
    if(serviceType.equalsIgnoreCase("EJB")){
    return new EJBService();
    }else {
    return new JMSService();
    }
    }
    }

    业务代表

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class BusinessDelegate {
    private BusinessLookUp lookupService = new BusinessLookUp();
    private BusinessService businessService;
    private String serviceType;
    public void setServiceType(String serviceType){
    this.serviceType = serviceType;
    }
    public void doTask(){
    businessService = lookupService.getBusinessService(serviceType);
    businessService.doProcessing();
    }
    }

    客户类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Client {
    BusinessDelegate businessService;
    public Client(BusinessDelegate businessService){
    this.businessService = businessService;
    }
    public void doTask(){
    businessService.doTask();
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class BusinessDelegatePatternDemo {
    public static void main(String[] args) {
    BusinessDelegate businessDelegate = new BusinessDelegate();
    businessDelegate.setServiceType("EJB");
    Client client = new Client(businessDelegate);
    client.doTask();
    businessDelegate.setServiceType("JMS");
    client.doTask();
    }
    }

组合实体模式

  1. 概括

    背景知识EJB持久化机制
    包装了很多层,据说与生命周期有关
    (客户端(组合实体(粗粒度对象(依赖对象,依赖对象))))

  2. 举例

    依赖对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class DependentObject1 {
    private String data;
    public void setData(String data){
    this.data = data;
    }
    public String getData(){
    return data;
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class DependentObject2 {
    private String data;
    public void setData(String data){
    this.data = data;
    }
    public String getData(){
    return data;
    }
    }

    粗粒度对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class CoarseGrainedObject {
    DependentObject1 do1 = new DependentObject1();
    DependentObject2 do2 = new DependentObject2();
    public void setData(String data1, String data2){
    do1.setData(data1);
    do2.setData(data2);
    }
    public String[] getData(){
    return new String[] {do1.getData(),do2.getData()};
    }
    }

    创建组合实体

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class CompositeEntity {
    private CoarseGrainedObject cgo = new CoarseGrainedObject();
    public void setData(String data1, String data2){
    cgo.setData(data1, data2);
    }
    public String[] getData(){
    return cgo.getData();
    }
    }

    创建使用组合实体的客户端类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    public class Client {
    private CompositeEntity compositeEntity = new CompositeEntity();
    public void printData(){
    for (int i = 0; i < compositeEntity.getData().length; i++) {
    System.out.println("Data: " + compositeEntity.getData()[i]);
    }
    }
    public void setData(String data1, String data2){
    compositeEntity.setData(data1, data2);
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class CompositeEntityPatternDemo {
    public static void main(String[] args) {
    Client client = new Client();
    client.setData("Test", "Data");
    client.printData();
    client.setData("Second Test", "Data1");
    client.printData();
    }
    }

数据访问对象模式

  1. 概括

    从业务操作中分离出较为低级的数据操作(可能是数据库,xml文件,其他)

  2. 举例

    相当于entity对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class Student {
    private String name;
    private int rollNo;
    Student(String name, int rollNo){
    this.name = name;
    this.rollNo = rollNo;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getRollNo() {
    return rollNo;
    }
    public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
    }
    }

    提前定义好数据访问的接口

    1
    2
    3
    4
    5
    6
    7
    import java.util.List;
    public interface StudentDao {
    public List<Student> getAllStudents();
    public Student getStudent(int rollNo);
    public void updateStudent(Student student);
    public void deleteStudent(Student student);
    }

    第二天才写好的实现类

    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
    import java.util.ArrayList;
    import java.util.List;
    public class StudentDaoImpl implements StudentDao {
    //列表是当作一个数据库
    List<Student> students;
    public StudentDaoImpl(){
    students = new ArrayList<Student>();
    Student student1 = new Student("Robert",0);
    Student student2 = new Student("John",1);
    students.add(student1);
    students.add(student2);
    }
    @Override
    public void deleteStudent(Student student) {
    students.remove(student.getRollNo());
    System.out.println("Student: Roll No " + student.getRollNo()
    +", deleted from database");
    }
    //从数据库中检索学生名单
    @Override
    public List<Student> getAllStudents() {
    return students;
    }
    @Override
    public Student getStudent(int rollNo) {
    return students.get(rollNo);
    }
    @Override
    public void updateStudent(Student student) {
    students.get(student.getRollNo()).setName(student.getName());
    System.out.println("Student: Roll No " + student.getRollNo()
    +", updated in the database");
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class DaoPatternDemo {
    public static void main(String[] args) {
    StudentDao studentDao = new StudentDaoImpl();
    //输出所有的学生
    for (Student student : studentDao.getAllStudents()) {
    System.out.println("Student: [RollNo : "
    +student.getRollNo()+", Name : "+student.getName()+" ]");
    }
    //更新学生
    Student student =studentDao.getAllStudents().get(0);
    student.setName("Michael");
    studentDao.updateStudent(student);
    //获取学生
    studentDao.getStudent(0);
    System.out.println("Student: [RollNo : "
    +student.getRollNo()+", Name : "+student.getName()+" ]");
    }
    }

前端控制器模式

  1. 概括

    前端来的请求均由前端控制器处理,
    而前端控制器可能借助调度器寻找最终处理者
    当然前端控制器除此之外不会什么都不干,比如身份验证,日志记录之类的

  2. 举例

    最终处理者,这里是用于显示视图的

    1
    2
    3
    4
    5
    public class HomeView {
    public void show(){
    System.out.println("Displaying Home Page");
    }
    }
    1
    2
    3
    4
    5
    public class StudentView {
    public void show(){
    System.out.println("Displaying Student Page");
    }
    }

    调度器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    public class Dispatcher {
    private StudentView studentView;
    private HomeView homeView;
    public Dispatcher(){
    studentView = new StudentView();
    homeView = new HomeView();
    }
    public void dispatch(String request){
    if(request.equalsIgnoreCase("STUDENT")){
    studentView.show();
    }else{
    homeView.show();
    }
    }
    }

    前端控制器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    public class FrontController {
    private Dispatcher dispatcher;
    public FrontController(){
    dispatcher = new Dispatcher();
    }
    private boolean isAuthenticUser(){
    System.out.println("User is authenticated successfully.");
    return true;
    }
    private void trackRequest(String request){
    System.out.println("Page requested: " + request);
    }
    public void dispatchRequest(String request){
    //记录每一个请求
    trackRequest(request);
    //对用户进行身份验证
    if(isAuthenticUser()){
    dispatcher.dispatch(request);
    }
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    public class FrontControllerPatternDemo {
    public static void main(String[] args) {
    FrontController frontController = new FrontController();
    frontController.dispatchRequest("HOME");
    frontController.dispatchRequest("STUDENT");
    }
    }

拦截过滤器模式

  1. 概括

    对请求做预处理/后处理等
    身份验证,日志记录,转码
    过滤器要组装过滤器链,设定终点等

  2. 举例

    过滤器统一接口

    1
    2
    3
    public interface Filter {
    public void execute(String request);
    }

    实际的过滤器

    1
    2
    3
    4
    5
    public class AuthenticationFilter implements Filter {
    public void execute(String request){
    System.out.println("Authenticating request: " + request);
    }
    }
    1
    2
    3
    4
    5
    public class DebugFilter implements Filter {
    public void execute(String request){
    System.out.println("request log: " + request);
    }
    }

    最终的处理,也就是终点

    1
    2
    3
    4
    5
    public class Target {
    public void execute(String request){
    System.out.println("Executing request: " + request);
    }
    }

    创建过滤器链的结构(还不知道过滤器链上都有什么)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import java.util.ArrayList;
    import java.util.List;
    public class FilterChain {
    private List<Filter> filters = new ArrayList<Filter>();
    private Target target;
    public void addFilter(Filter filter){
    filters.add(filter);
    }
    public void execute(String request){
    for (Filter filter : filters) {
    filter.execute(request);
    }
    target.execute(request);
    }
    public void setTarget(Target target){
    this.target = target;
    }
    }

    过滤器链管理器
    提供了一个接受请求的方法,其他都是抄袭过滤器链的方法

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class FilterManager {
    FilterChain filterChain;
    public FilterManager(Target target){
    filterChain = new FilterChain();
    filterChain.setTarget(target);
    }
    public void setFilter(Filter filter){
    filterChain.addFilter(filter);
    }
    public void filterRequest(String request){
    filterChain.execute(request);
    }
    }

    请求发送方,使用管理器来发送请求

    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Client {
    FilterManager filterManager;
    public void setFilterManager(FilterManager filterManager){
    this.filterManager = filterManager;
    }
    public void sendRequest(String request){
    filterManager.filterRequest(request);
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class InterceptingFilterDemo {
    public static void main(String[] args) {
    FilterManager filterManager = new FilterManager(new Target());
    filterManager.setFilter(new AuthenticationFilter());
    filterManager.setFilter(new DebugFilter());
    Client client = new Client();
    client.setFilterManager(filterManager);
    client.sendRequest("HOME");
    }
    }

服务定位器模式

  1. 概括

    JNDI?
    为服务查找JNDI,首次新建,之后从缓存中提取

  2. 举例

    服务的接口与实体类

    1
    2
    3
    4
    public interface Service {
    public String getName();
    public void execute();
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Service1 implements Service {
    public void execute(){
    System.out.println("Executing Service1");
    }
    @Override
    public String getName() {
    return "Service1";
    }
    }
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public class Service2 implements Service {
    public void execute(){
    System.out.println("Executing Service2");
    }
    @Override
    public String getName() {
    return "Service2";
    }
    }

    为 JNDI 查询创建 InitialContext。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class InitialContext {
    public Object lookup(String jndiName){
    if(jndiName.equalsIgnoreCase("SERVICE1")){
    System.out.println("Looking up and creating a new Service1 object");
    return new Service1();
    }else if (jndiName.equalsIgnoreCase("SERVICE2")){
    System.out.println("Looking up and creating a new Service2 object");
    return new Service2();
    }
    return null;
    }
    }

    创建缓存 Cache。

    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
    import java.util.ArrayList;
    import java.util.List;
    public class Cache {
    private List<Service> services;
    public Cache(){
    services = new ArrayList<Service>();
    }
    public Service getService(String serviceName){
    for (Service service : services) {
    if(service.getName().equalsIgnoreCase(serviceName)){
    System.out.println("Returning cached "+serviceName+" object");
    return service;
    }
    }
    return null;
    }
    public void addService(Service newService){
    boolean exists = false;
    for (Service service : services) {
    if(service.getName().equalsIgnoreCase(newService.getName())){
    exists = true;
    }
    }
    if(!exists){
    services.add(newService);
    }
    }
    }

    创建服务定位器

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public class ServiceLocator {
    private static Cache cache;
    static {
    cache = new Cache();
    }
    public static Service getService(String jndiName){
    Service service = cache.getService(jndiName);
    if(service != null){
    return service;
    }
    InitialContext context = new InitialContext();
    Service service1 = (Service)context.lookup(jndiName);
    cache.addService(service1);
    return service1;
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    public class ServiceLocatorPatternDemo {
    public static void main(String[] args) {
    Service service = ServiceLocator.getService("Service1");
    service.execute();
    service = ServiceLocator.getService("Service2");
    service.execute();
    service = ServiceLocator.getService("Service1");
    service.execute();
    service = ServiceLocator.getService("Service2");
    service.execute();
    }
    }

传输对象模式

  1. 概括

    POJO?
    传输对象是简单的bean
    用业务对象装着
    业务对象则定义了很多高级的方法

  2. 举例

    传输对象

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    public class StudentVO {
    private String name;
    private int rollNo;
    StudentVO(String name, int rollNo){
    this.name = name;
    this.rollNo = rollNo;
    }
    public String getName() {
    return name;
    }
    public void setName(String name) {
    this.name = name;
    }
    public int getRollNo() {
    return rollNo;
    }
    public void setRollNo(int rollNo) {
    this.rollNo = rollNo;
    }
    }

    业务对象
    算是定义了对数据对象和数据库间对接的操作

    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
    import java.util.ArrayList;
    import java.util.List;
    public class StudentBO {
    //列表是当作一个数据库
    List<StudentVO> students;
    public StudentBO(){
    students = new ArrayList<StudentVO>();
    StudentVO student1 = new StudentVO("Robert",0);
    StudentVO student2 = new StudentVO("John",1);
    students.add(student1);
    students.add(student2);
    }
    public void deleteStudent(StudentVO student) {
    students.remove(student.getRollNo());
    System.out.println("Student: Roll No "
    + student.getRollNo() +", deleted from database");
    }
    //从数据库中检索学生名单
    public List<StudentVO> getAllStudents() {
    return students;
    }
    public StudentVO getStudent(int rollNo) {
    return students.get(rollNo);
    }
    public void updateStudent(StudentVO student) {
    students.get(student.getRollNo()).setName(student.getName());
    System.out.println("Student: Roll No "
    + student.getRollNo() +", updated in the database");
    }
    }

    使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class TransferObjectPatternDemo {
    public static void main(String[] args) {
    StudentBO studentBusinessObject = new StudentBO();
    //输出所有的学生
    for (StudentVO student : studentBusinessObject.getAllStudents()) {
    System.out.println("Student: [RollNo : "
    +student.getRollNo()+", Name : "+student.getName()+" ]");
    }
    //更新学生
    StudentVO student =studentBusinessObject.getAllStudents().get(0);
    student.setName("Michael");
    studentBusinessObject.updateStudent(student);
    //获取学生
    studentBusinessObject.getStudent(0);
    System.out.println("Student: [RollNo : "
    +student.getRollNo()+", Name : "+student.getName()+" ]");
    }
    }

参考

程序员必知设计模式
https://blog.csdn.net/yaolingrui/article/details/7338263
http://www.runoob.com/design-pattern/mvc-pattern.html
参考书
Design Patterns - Elements of Reusable Object-Oriented Software
设计模式-可复用的面向对象软件元素