金三银四专属复习篇之设计模式(下篇)

5)工厂模式

遵循依赖抽象原则

变量不要持有具体类的引用;不要让类继承自具体类,要继承自抽象类或接口;不要覆盖基类中已经实现的方法。

5.1 简单工厂模式

定义了一个创建对象的类,由这个类来封装实例化对象的行为

问题:如一家披萨店,在下订单时会根据不同的披萨实例化不同的对象,这样以后每次提出新品种或者下架某品种,就要去修改订单里面的实例化操作。

如下可以定义一个简单的工厂类来封装实例化过程

/**
 * 简单工厂模式
 */
public class SimplePizzaFactory {
    /**
     * 传入披萨的类型
     *
     * @param ordertype
     * @return
     */
    public Pizza CreatePizza(String ordertype) {
        Pizza pizza = null;
​
        if (ordertype.equals("cheese")) {
            pizza = new CheesePizza();
        } else if (ordertype.equals("greek")) {
            pizza = new GreekPizza();
        } else if (ordertype.equals("pepper")) {
            pizza = new PepperPizza();
        }
        return pizza;
    }
}



/**
 * 披萨订单模块
 */
public class OrderPizza {
   SimplePizzaFactory mSimplePizzaFactory;
​
   public OrderPizza(SimplePizzaFactory mSimplePizzaFactory) {
      setFactory(mSimplePizzaFactory);
   }
​
   public void setFactory(SimplePizzaFactory mSimplePizzaFactory) {
      Pizza pizza = null;
      String ordertype;
      this.mSimplePizzaFactory = mSimplePizzaFactory;
      //工厂生产披萨并进行包装发货
      do {
         ordertype = gettype();
         pizza = mSimplePizzaFactory.CreatePizza(ordertype);
         if (pizza != null) {
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
         }
      } while (true);
   }
​
   private String gettype() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(
               System.in));
         System.out.println("input pizza type:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }
}
 

/**
 * 披萨店中购买披萨
 */
public class PizzaStroe {
   public static void main(String[] args) {
      SimplePizzaFactory mSimplePizzaFactory;
      OrderPizza mOrderPizza;
      mOrderPizza=new OrderPizza(new SimplePizzaFactory());
   }
}

5.2 方法工厂模式

定义了一个创建对象的抽象方法,由子类决定要实例化的类。

问题:如果一家披萨店要在全国开连锁,这样地方的配料肯定不一样,所以单纯的将工厂复制过去是不行的。

如下可以将创建披萨的方法抽象化,让子类继承后去实例化具体的对象

/**
 * 抽象化下订单的模块
 */
public abstract class OrderPizza {
    public OrderPizza() {
        Pizza pizza = null;
        String ordertype;
        do {
            ordertype = gettype();
            pizza = createPizza(ordertype);
​
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
        } while (true);
    }
​
    abstract Pizza createPizza(String ordertype);
​
    private String gettype() {
        try {
            BufferedReader strin = new BufferedReader(new InputStreamReader(
                    System.in));
            System.out.println("input pizza type:");
            String str = strin.readLine();
            return str;
        } catch (IOException e) {
            e.printStackTrace();
            return "";
        }
    }
}
 

/**
 * 伦敦的披萨店
 */
public class LDOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String ordertype) {
        Pizza pizza = null;
        if (ordertype.equals("cheese")) {
            pizza = new LDCheesePizza();
        } else if (ordertype.equals("pepper")) {
            pizza = new LDPepperPizza();
        }
        return pizza;
    }
}
 

/**
 * 纽约的披萨店
 */
public class NYOrderPizza extends OrderPizza {
    @Override
    Pizza createPizza(String ordertype) {
        Pizza pizza = null;
        if (ordertype.equals("cheese")) {
            pizza = new NYCheesePizza();
        } else if (ordertype.equals("pepper")) {
            pizza = new NYPepperPizza();
        }
        return pizza;
    }
}
 

/**
 * 披萨店中购买披萨
 */
public class PizzaStroe {
   public static void main(String[] args) {
      OrderPizza mOrderPizza;
      mOrderPizza=new NYOrderPizza();
   }
}

5.3 抽象工厂模式

定义了一个接口用于创建相关或有依赖关系的对象族,而无需明确指定具体类。

/**
 * 抽象工厂模式
 */
public interface AbsFactory {
   public Pizza CreatePizza(String ordertype) ;
}
 

/**
 * 伦敦工厂
 */
public class LDFactory implements AbsFactory {
   @Override
   public Pizza CreatePizza(String ordertype) {
      Pizza pizza = null;
      if (ordertype.equals("cheese")) {
         pizza = new LDCheesePizza();
      } else if (ordertype.equals("pepper")) {
         pizza = new LDPepperPizza();
      }
      return pizza;
   }
}
 

/**
 * 纽约工厂
 */
public class NYFactory implements AbsFactory {
   @Override
   public Pizza CreatePizza(String ordertype) {
      Pizza pizza = null;
      if (ordertype.equals("cheese")) {
         pizza = new NYCheesePizza();
      } else if (ordertype.equals("pepper")) {
         pizza = new NYPepperPizza();
      }
      return pizza;
   }
}
 

/**
 * 下订单的模块
 */
public class OrderPizza {
   AbsFactory mFactory;
​
   public OrderPizza(AbsFactory mFactory) {
      setFactory(mFactory);
   }
​
   public void setFactory(AbsFactory mFactory) {
      Pizza pizza = null;
      String ordertype;
      this.mFactory = mFactory;
      do {
         ordertype = gettype();
         pizza = mFactory.CreatePizza(ordertype);
         if (pizza != null) {
            pizza.prepare();
            pizza.bake();
            pizza.cut();
            pizza.box();
         }
      } while (true);
   }
​
   private String gettype() {
      try {
         BufferedReader strin = new BufferedReader(new InputStreamReader(
               System.in));
         System.out.println("input pizza type:");
         String str = strin.readLine();
         return str;
      } catch (IOException e) {
         e.printStackTrace();
         return "";
      }
   }
}
 

/**
 * 披萨店中购买披萨
 */
public class PizzaStroe {
   public static void main(String[] args) {
      OrderPizza mOrderPizza;
      mOrderPizza=new OrderPizza(new LDFactory());
   }
}

6)策略模式
分别封装行为接口,实现算法族,超类里放行为接口对象,在子类里具体设置行为对象。

策略模式注重功能实现。

原则:分离变化部分,封装接口,基于接口编程各种功能,此模式让行为算法的变化独立于算法的使用者。

将行为定义为接口

/**
 * 飞行
 */
public interface FlyBehavior {
   void fly();
}
具体的实现类:

/**
 * 会飞
 */
public class GoodFlyBehavior implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("--GoodFly--");
    }
}
 

/**
 * 不会飞
 */
public class NoFlyBehavior implements FlyBehavior {
    @Override
    public void fly() {
        System.out.println("--NoFly--");
    }
}

如果还有其他行为也可以向上面一样,先定义接口,在实现,比如叫声可以分呱呱叫还有其他叫。

定义一个鸭子类:

/**
 * 鸭子
 */
public abstract class Duck {
   /**
    * 飞行
    */
   FlyBehavior mFlyBehavior;
   
   /**
    * 叫声
    */
   QuackBehavior mQuackBehavior;
​
   public abstract void display();
​
   public Duck() {
​
   }
​
   public void Fly() {
      mFlyBehavior.fly();
   }
​
   public void Quack() {
      mQuackBehavior.quack();
   }
​
   public void SetQuackBehavoir(QuackBehavior qb) {
      mQuackBehavior = qb;
   }
​
   public void SetFlyBehavoir(FlyBehavior fb) {
      mFlyBehavior = fb;
   }
​
   public void swim() {
      System.out.println("~~im swim~~");
   }
}

鸭子下的子类:

/**
 * 绿头鸭
 */
public class GreenHeadDuck extends Duck {
    public GreenHeadDuck() {
        //实例化具体的飞行方式
        mFlyBehavior = new GoodFlyBehavior();
        //实例化具体的叫声
        mQuackBehavior = new GaGaQuackBehavior();
    }
​
    @Override
    public void display() {
        System.out.println("**GreenHead**");
    }
}

这样就能实现按不同需求实现:

public class StimulateDuck {
    public static void main(String[] args) {
        GreenHeadDuck mGreenHeadDuck = new GreenHeadDuck();
        RedHeadDuck mRedHeadDuck = new RedHeadDuck();
​
        mGreenHeadDuck.display();
        mGreenHeadDuck.Fly();
        mGreenHeadDuck.Quack();
        mGreenHeadDuck.swim();
​
        mRedHeadDuck.display();
        mRedHeadDuck.Quack();
        mRedHeadDuck.swim();
        mRedHeadDuck.Fly();
    }
}

7)模板模式
封装了一个算法步骤,并允许子类为一个或多个步骤方法提供实现;模板模式可以使子类在不改变算法结构的情况下,重新定义算法中的某些步骤

模板模式注重步骤实现。

/**
 * @author: 肖德子裕
 * @date: 2019/03/03 19:31
 * @description: 模板模式
 */
public abstract class HotDrinkTemplate {
    /**
     * 这是一个模板方法
     */
    public final void prepareRecipe() {
        //烧水,固定
        boilWater();
        //喝什么,由子类实现
        brew();
        //加水,固定
        pourInCup();
        //通过钩子方法,让子类确定是否配料
        if (wantCondimentsHook()) {
            //加配料
            addCodiments();
        } else {
            System.out.println("不加配料");
        }
    }
​
    /**
     * 钩子方法
     *
     * @return
     */
    public boolean wantCondimentsHook() {
        return true;
    }
​
    public final void boilWater() {
        System.out.println("Boiling water");
    }
​
    public abstract void brew();
​
    public final void pourInCup() {
        System.out.println("put in cup");
    }
​
    public abstract void addCodiments();
}
 

/**
 * @author: 肖德子裕
 * @date: 2019/03/03 19:52
 * @description: 泡茶
 */
public class TeaWithHook extends HotDrinkTemplate{
    @Override
    public boolean wantCondimentsHook() {
        System.out.println("y/n:");
        BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
        String result="";
        try {
            result=in.readLine();
        }catch (IOException e){
            e.printStackTrace();
        }
        if (result.equals("n")){
            return false;
        }
        return true;
    }
​
    @Override
    public void brew() {
        System.out.println("泡茶");
    }
​
    @Override
    public void addCodiments() {
        System.out.println("加柠檬");
    }
}
 

/**
 * @author: 肖德子裕
 * @date: 2019/03/03 19:58
 * @description: 测试
 */
public class Main {
    public static void main(String[] args) {
        TeaWithHook tea=new TeaWithHook();
        tea.prepareRecipe();
    }
}

模板方法模式的优点

  • 封装不变的内容,扩展可变部分,如果我们要添加一个H3悍马模型,只需要继承父类就可以了。

  • 提取公共部分代码,便于维护

  • 行为由父类控制,子类实现。基本方法是由子类实现的,因此子类可以通过拓展的方法增加相应的功能,符合开闭原则。

模板方法模式的使用场景

  • 多个子类有公有的方法,并且逻辑基本相同时

  • 重复、复杂的算法,可以把核心算法设计为模板方法,周边的细节则有各个子类实现

  • 代码重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后用钩子方法约束其行为。

在这里插入图片描述

在这里插入图片描述

需要更多java架构学习资料以及面试题的群搜索“708701457” 备注CSDN

猜你喜欢

转载自blog.csdn.net/qq_42982923/article/details/88355745