关于设计模式:面试题设计模式

44次阅读

共计 15722 个字符,预计需要花费 40 分钟才能阅读完成。

什么是设计模式

设计模式,是一套被重复应用、少数人通晓的、通过分类编目标、代码设计教训的总结。应用设计模式是为了可重用代码、让代码更容易被别人了解、保障代码可靠性、程序的重用性。

为什么要学习设计模式

设计模式的实质是面向对象设计准则的理论使用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充沛了解

  • 能够进步程序员的思维能力、编程能力和设计能力。
  • 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
  • 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。

设计模式分类

大体能够分为三种,每种加起又能够细分为 23 种。

  • 创立型模式,共五种:工厂办法模式、形象工厂模式、单例模式、建造者模式、原型模式。
  • 结构型模式,共七种:适配器模式、装璜器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
  • 行为型模式,共十一种:策略模式、模板办法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。

设计模式的六大准则

凋谢关闭准则

  • 准则思维:尽量通过扩大软件实体来解决需要变动,而不是通过批改已有的代码来实现变动
  • 形容:一个软件产品在生命周期内,都会发生变化,既然变动是一个既定的事实,咱们就应该在设计的时候尽量适应这些变动,以进步我的项目的稳定性和灵活性。
  • 长处:繁多准则通知咱们,每个类都有本人负责的职责,里氏替换准则不能毁坏继承关系的体系。

里氏代换准则

  • 准则思维:应用的基类能够在任何中央应用继承的子类,完满的替换基类。
  • 大略意思是:子类能够扩大父类的性能,但不能扭转父类原有的性能。子类能够实现父类的形象办法,但不能笼罩父类的非形象办法,子类中能够减少本人特有的办法。
  • 长处:减少程序的健壮性,即便减少了子类,原有的子类还能够持续运行,互不影响。

依赖倒转准则

  • 依赖倒置准则的核心思想是面向接口编程.
  • 依赖倒转准则要求咱们在程序代码中传递参数时或在关联关系中,尽量援用档次高的形象层类,
  • 这个是凋谢关闭准则的根底,具体内容是:对接口编程,依赖于形象而不依赖于具体。

接口隔离准则

  • 这个准则的意思是:应用多个隔离的接口,比应用单个接口要好。还是一个升高类之间的耦合度的意思,从这儿咱们看出,其实设计模式就是一个软件的设计思维,从大型软件架构登程,为了降级和保护不便。所以上文中屡次呈现:升高依赖,升高耦合。
  • 例如:领取类的接口和订单类的接口,须要把这俩个类别的接口变成俩个隔离的接口

迪米特法令(起码晓得准则)

  • 准则思维:一个对象该当对其余对象有尽可能少地理解,简称类间解耦
  • 大略意思就是一个类尽量减少本人对其余对象的依赖,准则是低耦合,高内聚,只有使各个模块之间的耦合尽量的低,能力进步代码的复用率。
  • 长处:低耦合,高内聚。

繁多职责准则

  • 准则思维:一个办法只负责一件事件。
  • 形容:繁多职责准则很简略,一个办法 一个类只负责一个职责,各个职责的程序改变,不影响其它程序。这是常识,简直所有程序员都会遵循这个准则。
  • 长处:升高类和类的耦合,进步可读性,减少可维护性和可拓展性,升高可变性的危险。

单例模式

什么是单例

保障一个类只有一个实例,并且提供一个拜访该全局拜访点

那些中央用到了单例模式

  1. 网站的计数器,个别也是采纳单例模式实现的,否则难以同步
  2. 应用程序的日志利用,个别也都是单例模式实现,只有一个实例去操作才好,否则内容不好最佳显示。
  3. 多线程的线程池的设计个别也是采纳单例模式,因为线程池要不便对池中的线程进行管制。
  4. Windows 的工作管理器就是厂房典型的单例模式,他不能关上两个
  5. Windows 的回收站也是经典的单例利用。在整个零碎运行过程中,回收站只能保护一个实例。

单例模式的优缺点

长处

  1. 在单例模式中,流动的单例只有一个实例,对单例类的所有实例化失去的都是雷同的一个实例。这样就避免其余对象对本人的实例化,确保所有的对象都拜访一个实例。
  2. 单例模式具备肯定的伸缩性,类本人来管制实例化过程,类就在扭转实例化过程上有相应的伸缩性。
  3. 提供了对惟一实例的受控拜访。
  4. 因为在零碎内存中只存在一个对象,因而能够节约系统资源,当须要频繁创立和销毁的对象时单例模式无疑能够提供零碎的性能。
  5. 容许可变数目标实例。
  6. 防止对共享资源的多重占用。

毛病

  1. 不适用于变动的对象,如果同一类型的对象总是要在不同的用例场景发生变化,单例就会引起数据的谬误,不能保留彼此的状态。
  2. 因为单例模式中没有形象层,因而单例的扩大有很大的艰难。
  3. 单例类的职责过重,在肯定程序上违反了“繁多职责准则”。
  4. 滥用单例将带来一些负面问题,如为了节俭资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而呈现连接池溢出;如果实例化的对象长时间不被利用,零碎会认为是垃圾而被回收,这将导致对象状态的失落。

单例模式应用注意事项

  1. 应用时不能用反射模式创立单例,否则会实例一个新的对象。
  2. 应用懒单例模式时留神线程平安问题。
  3. 饿单例模式和懒单例模式构造方法都是公有的,因而是不能被继承的,有些单例模式能够被继承(如注销式模式)

单例避免反射破绽攻打

private static boolean flag = false;

private Singleton() {if (flag == flase) {flag = !flag;} eLse {thrown new RuntimeException("单例模式被进犯!");
    }
}

如何抉择单例创立形式

如果不须要提早加载单例,能够应用枚举或者饿汉式,相对来说枚举性好于饿汉式。如果须要提早加载,能够应用动态外部类或者懒汉式,相对来说动态外部类好于懒汉式。

单例创立形式

  1. 饿汉式:类初始化时,会立刻加载该对象,线程天生平安,调用效率高。
  2. 懒汉式:类初始化时,不会初始化该对象,真正须要应用的时候才会创立该对象,具备懒加载性能。
  3. 动态外部形式:联合了懒汉式和饿汉式格子的长处,真正须要对象的时候才会加载,加载相似线程平安的。
  4. 枚举单例:应用枚举实现单例模式

    • 长处:实现简略、调用效率高,枚举自身就是单例,因为 JVM 从根本上提供保障!防止通过反射和反序列化的破绽
    • 毛病:没有提早加载
  5. 双重检测锁形式:因为 JVM 实质重排序的起因,可能会初始化屡次,不举荐应用

饿汉式

类初始化时,会立刻加载该对象,线程天生平安,调用效率高。

public class Demo1 {private static Demo1 demo1 = new Demo1();

    private Demo1() {System.out.println("公有 Demo1 结构参数初始化");
    }

    public static Demo1 getInstance() {return demo1;}

    public static void main(String[] args) {Demo1 s1 = Demo1.getInstance();
        Demo1 s2 = Demo1.getInstance();
        System.out.println(s1 == s2);
    }
}

懒汉式

类初始化时,不会初始化该对象,真正须要应用的时候才会创立该对象,具备懒加载性能。

public class Demo2 {
    private static Demo2 demo2;

    private Demo2() {System.out.println("公有 Demo2 结构参数初始化");
    }

    public synchronized static Demo2 getInstance () {if (demo2 == null) {demo2 = new Demo2();
        }
        return demo2;
    }

    public static void main(String[] args) {Demo2 s1 = Demo2.getInstance();
        Demo2 s2 = Demo2.getInstance();
        System.out.println(s1 == s2);
    }
}

动态外部类

动态外部类形式:联合了懒汉式和饿汉式格子的长处,真正须要对象的时候才会加载,加载类是线程平安的。

public class Demo3 {private Demo3() {System.out.println("Demo 的公有结构参数办法");
    }

    public static class SingletonClassInstance{private static final Demo3 DEMO_3 = new Demo3();
    }

    public static Demo3 getInstance() {return SingletonClassInstance.DEMO_3;}

    public static void main(String[] args) {Demo3 s1 = Demo3.getInstance();
        Demo3 s2 = Demo3.getInstance();
        System.out.println(s1 == s2);
    }
}

枚举单例式

应用枚举实现单例模式
长处:实现简略,调用效率高,枚举自身就是单例,由 JVM 从根本上提供保障!防止通过反射和反序列化的破绽
毛病:没有提早加载

工厂模式

什么是工厂模式

它提供了一种创建对象的最佳形式。在工厂模式中,咱们创建对象时不会对客户端裸露创立逻辑,并且是通过应用一个独特的接口来指向新创建的对象。实现了创建者和调用者拆散,工厂模式分为简略工厂、工厂办法、形象工程模式

工厂模式益处

  1. 工厂模式时咱们最罕用的实例化对象模式了,是用工厂办法代替 new 操作的一种模式。
  2. 利用工厂模式能够升高程序的耦合性,为前期的保护批改提供了很大的便当。
  3. 将抉择实现类、创建对象对立治理和管制。从而将调用者跟我妈的实现类解耦。

Spring 开发中的工厂设计模式

  1. Spring IOC

    • 看过 Spring 源码就晓得,在 SpringIOC 容器创立 bean 的过程是应用了工厂设计模式。
    • Spring 中无论是通过 xml 配置还是通过配置类还是通过注解进行创立 bean,大部分都是通过简略工厂来进行创立的。
    • 当容器拿到了 beanName 和 class 类型后,动静的通过反射创立具体的某个对象,最初将创立的指向放到 map 中。

为什么 Spring IOC 要应用工厂设计模式创立 Bean 呢?

  1. 在理论开发中,如果咱们 A 对象调用 B,B 调用 C,C 调用 D 的话咱们程序的耦合性就会变高。
  2. 在很久以前的三层架构编程时,都是管制层调用业务层,业务层调用数据拜访层时,都是间接 new 对象,耦合性大大晋升,代码反复量很高,对象满天飞。
  3. 为了防止这种状况,Spring 应用工厂模式编程,写一个工厂,由工厂创立 Bean,当前咱们如果要对象就间接管工厂要就能够了,剩下的事件不归咱们管了.Spring IOC 容器的工厂中有个动态的 Map 汇合,是为了让工厂合乎单例设计模式,即每个对象只生产一次,生产出对象后就存入到 Map 汇合中,保障了实例不会反复影响程序效率。

工厂模式分类

  1. 简略工厂:用来生产同一等级构造中的任意产品
  2. 工厂办法:用来生产同一等级构造中的固定产品
  3. 形象工厂:用来生产不同产品组族的全副产品。

简略工厂模式

什么是简略工厂模式

简略工厂模式相等于是一个工厂中有各种产品,创立在一个类中,客户无需晓得具体产品的名称,只须要晓得产品类说对应失去参数即可。然而工厂的职责过重,而且当类型过多时不利于零碎的扩大保护。

代码演示:

  1. 创立工厂

    public interface Car {public void run();
    }
  2. 创立工厂的产品(如果为宝马)

    public class Bmw implements Car {
    @Override
    public void run() {System.out.println("我是宝马汽车......");
        }
    }
  3. 创立工厂中的另外一种产品(如果为奥迪)

    public class AoDi implements Car{
    @Override
    public void run() {System.out.println("我是奥迪汽车......");
        }
    }
  4. 创立外围工厂类,有他决定具体调用哪个产品

    public class CarFactory {public static Car createCar(String name) {if ("".equals(name)) {return null;}
        if (name.equals("奥迪")) {return new AoDi();
        }
        if (name.equals("宝马")) {return new Bmw();
        }
        return null;
        }
    }
  5. 演示创立工厂的具体实例

    public class Client01 {public static void main(String[] args) {Car aoDi = CarFactory.createCar("奥迪");
        Car bmw = CarFactory.createCar("宝马");
        aoDi.run();
        bmw.run();;}
    }

    单工厂的长处 / 毛病:
    长处:简略工厂模式可能依据外界给定的信息,决定到底应该创立哪个具体类的对象。明确辨别了各自的职责和势力,有利于整个软件体系结构的优化。
    毛病:很显著工厂类集中了所有实例的创立逻辑,容易违反高汇集的责任分配原则。

工厂办法模式

什么是工厂办法模式

工厂办法模式,又称为多态性工厂模式。在工厂办法模式中,外围的工厂类不在负责所有的产品的创立,而是将具体创立的工作交给子类去做。该外围类成为一个形象工厂角色,仅负责给出具体工厂子类必须实现的接口,而不接触哪一个产品类该当被实例化的这种细节。

代码演示:

  1. 创立工厂:

    public interface Car {public void run();
    }
  2. 创立工厂办法调用接口(所有的产品须要 new 进去必须继承他来实现办法)

    public interface CarFactory {Car createCar();
    }
  3. 创立工厂的第一种产品(假如为奥迪)

    public class AoDi implements Car{
    @Override
    public void run() {System.out.println("我是奥迪汽车......");
        }
    }
  4. 创立工厂中的另外一个产品(假如为宝马)

    public class Bmw implements Car{
    @Override
    public void run() {System.out.println("我是宝马汽车......");
        }
    }
  5. 创立工厂办法调用接口的实例(奥迪)

    public class AoDiFactory implements CarFactory{
    @Override
    public Car createCar() {return new AoDi();
        }
    }
  6. 创立工厂办法调用接口的实例(宝马)

    public class BmwFactory implements CarFactory{
    @Override
    public Car createCar() {return new Bmw();
        }
    }
  7. 演示创立工厂的具体实例

    public class Client {public static void main(String[] args) {Car aodi = new AoDiFactory().createCar();
        Car bmw = new BmwFactory().createCar();
        aodi.run();
        bmw.run();}
    }

形象工厂模式

什么是形象工厂模式

形象工厂简略地说是工厂的工厂,形象工厂能够创立具体工厂,由具体工厂来产品具体产品。

代码演示:

  1. 创立第一个子工厂,及实现类

    public interface Car {void run();
    }
    
    class CarA implements Car {
    
        @Override
        public void run() {System.out.println("宝马");
        }
    }
    
    class CarB implements Car {
        @Override
        public void run() {System.out.println("摩拜");
        }
    }
  2. 创立第二个子工厂,及实现类

    public interface Engine {void run();
    }
    
    class EngineA implements Engine {
        @Override
        public void run() {System.out.println("转的很快!");
        }
    }
    
    class EngineB implements Engine {
        @Override
        public void run() {System.out.println("转的慢!");
        }
    }
  3. 创立一个总工厂,及实现类(由总工厂的实现类决定调用那个工厂的那个实例)

    public interface TotalFactory {
    // 创立汽车
    Car createChair();
    
    // 创立发动机
    Engine createEngine();}
    
    class TotalFactoryReally implements TotalFactory {public Engine createEngine() {return new EngineA();
        }
    
        public Car createChair() {return new CarA();
        }
    }
  4. 运行测试

    public class Client {public static void main(String[] args) {TotalFactory totalFactory = new TotalFactoryReally();
        Car car = totalFactory.createChair();
        car.run();
    
        TotalFactory factoryReally = new TotalFactoryReally();
        Engine engine = factoryReally.createEngine();
        engine.run();}
    }

代理模式

什么是代理模式

  1. 通过代理管制对象的拜访,能够在这个对象调用办法之前、调用办法之后去解决 / 增加新的性能。(也就是 AOP 的微实现)
  2. 代理在原有代码乃至原业务流程都不批改的状况下,间接在业务流程中切入行新代码,减少新性能,这也和 Spring(面向切面编程)很类似。

代理模式利用场景

Spring AOP、日志打印、异样解决、事务管制、权限管制等等

代理的分类

  1. 动态代理(动态定义代理类)
  2. 动静代理(动静生成代理类,也称为 JDK 自带动静代理)
  3. Cglib、javaassist(字节码操作库)

三种代理的区别

  1. 动态代理:简略代理模式,是动静代理的实践根底。常见应用在代理模式。
  2. JDK 动静代理:应用反射实现代理。须要有顶层接口能力应用,常见是 myabtis 的 mapper 文件是代理。
  3. cglib 动静代理:也是应用反射实现代理,能够间接代理类(jdk 动静代理不行),应用字节码技术,不能对 final 类进行继承。(须要导入 jar 包)

用代码演示三种代理

动态代理

什么是动态代理

由程序员创立或工具生成代理类的源码,再编译代理类。所谓动态也就是程序运行前就曾经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

我有一段这样的代码:(如何能在不批改 UserDao 接口类的状况下开事务和敞开事务呢)

public class UserDao {public void save() {System.out.println("保留数据办法");
    }
}
public class Test {public static void main(String[] args) {UserDao userDao = new UserDao();
        userDao.save();}
}

批改代码,增加代理类

public class UserDaoProxy extends UserDao{
    private UserDao userDao;

    public UserDaoProxy(UserDao userDao) {this.userDao = userDao;}

    public void save() {System.out.println("开启事务...");
        userDao.save();
        System.out.println("敞开事务...");
    }
}
public class ProxyTest {public static void main(String[] args) {UserDao userDao = new UserDao();
        UserDaoProxy userDaoProxy = new UserDaoProxy(userDao);
        userDaoProxy.save();}
}
  • 长处:能够面相理论对象或者是接口的形式实现代理
  • 毛病:每个须要代理的对象都须要本人反复编写代理,很不难受。

动静代理

什么是动静代理

  • 动静代理也叫做,JDK 代理、接口代理。
  • 动静代理的对象,是利用 JDK 的 API,动静的在内存中构建代理对象(是依据被代理的接口来动静生成代理类的 class 文件,并加载运行的过程),这就叫动静代理。
    源代码:

    public interface UserDao {void save();
    }
    public class UserDaoImpl implements UserDao{
      @Override
      public void save() {System.out.println("保留数据办法");
      }
    }

    上面是代理类,可重复使用,不像动态代理那样要本人反复编写代理。

    /**
     * 每次生成动静代理类对象,实现了 InvocationHandler 接口的调用处理器对象
     */
    public class InvocationHandlerImpl implements InvocationHandler {
    
      /**
       * 这位业务实现类对象,用来调用具体的业务办法
       */
      private Object target;
    
      /**
       * 通过构造函数传入指标对象
       */
      public InvocationHandlerImpl(Object target) {this.target = target;}
    
      /**
       * 动静代理理论运行的代理办法
       */
      @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("调用开始解决");
          // 上面 invoke()办法是以反射的形式来创建对象,第一个参数是要创立的对象,第二个是形成办法的参数,由第二个参数决定创立指向应用哪个构造方法
          Object result = method.invoke(target, args);
          System.out.println("调用完结解决");
          return result;
      }
    }
    public class Test {public static void main(String[] args) {
          // 被代理对象
          UserDao userDao = new UserDaoImpl();
          InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userDao);
          // 类加载器
          ClassLoader loader = userDao.getClass().getClassLoader();
          Class<?>[] interfaces = userDao.getClass().getInterfaces();
          // 次要装载器、一组接口及调用解决动静代理实例
          UserDao newProxyInstance = (UserDao) Proxy.newProxyInstance(loader, interfaces, invocationHandler);
          newProxyInstance.save();}
    }
  • 毛病:必须是面向接口,指标业务类必须实现接口。
  • 长处:不必关怀代理类,只须要在运行阶段才指定代码哪一个对象。

CGLIB 动静代理

CGLI 动静代理原理

利用 asm 开源包,对代理对象类的 class 文件加载进来,通过批改其字节码生成之类来解决。

什么是 CGLIB 动静代理

CGLIB 动静代理和 jdk 代理一样,应用反射实现代理,不同的是他能够间接代理类(jdk 代理不行,他必须指标业务类必须实现接口),CGLIB 动静代理底层应用字节码技术,CGLIB 动静代理通能对 final 类进行继承。(CGLIB 动静代理须要导入 jar 包)

代码演示:

源代码:

public interface UserDao {void save();
}
public class UserDaoImpl implements UserDao{
    @Override
    public void save() {System.out.println("保留数据的办法");
    }
}

退出代理类:

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * 代理次要类
 */
public class CglibProxy implements MethodInterceptor {

    private Object targetObject;

    /**
     * 这里的指标类型为 Object,则能够承受任意一种参数作为被代理类,实现了动静代理
     */
    public Object getInstance(Object target) {
        // 设置须要创立子类的类
        this.targetObject = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();}

    /**
     * 代理的理论办法
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("开启事务");
        Object result = methodProxy.invoke(targetObject, objects);
        System.out.println("敞开事务");
        return result;
    }
}
public class Test {public static void main(String[] args) {CglibProxy cglibProxy = new CglibProxy();
        UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
        userDao.save();}
}

建造者模式

什么是建造者模式

  1. 建造者模式:是将一个简单的对象的构建与它的示意拆散,使得同样的构建过程能够创立不同的形式进行创立。
  2. 工厂类模式提供的是创立单个类的产品,而建造者模式这是将各种产品集中起来进行治理,用来具备不同的属性的产品。

建造者模式通常包含上面几个角色

  1. Builder:给出一个形象接口,以标准产品对象的各个组成成分的建造。这个接口规定要实现简单对象的哪些局部的创立,并不波及具体的对象部件的创立。
  2. ConcreteBuilder:实现 Builder 接口,针对不同的商业逻辑,具体化简单对象的各局部的创立。在建造过程实现后,提供产品的实例。
  3. Director:调用具体建造者来创立简单对象的各个局部,在指导者中不波及具体产品的信息,只负责保障对象各局部残缺创立或按某种程序创立。
  4. Product:要创立的简单对象

建造者模式的应用场景

应用场景

  1. 须要生成的对象具备简单的内部结构。
  2. 须要生成的对象外部属性自身相互依赖。
  • 与工厂模式的区别是:建造者模式更加关注与整机拆卸的程序。
  • Java 中的 StringBuilder 就是建造者模式创立的,他吧一个单个只剩的 char 数组组合起来。
  • Spring 不是建造者模式,他提供的操作应该是对于字符串自身的一些操作,而不是创立或扭转一个字符串。

代码演示:

  1. 建设一个配备对象 Arms

    import lombok.Data;
    
    /**
     * 配备类
     */
    @Data
    public class Arms {
        // 头盔
        private String helmet;
        // 铠甲
        private String armor;
        // 武器
        private String weapon;
    }
  2. 创立 Builder 接口(给出一个形象接口,以标准产品对象的各个组成成分的建造,这个接口只是标准)

    public interface PersonBuilder {void builderHelmetMurder();
    void builderArmorMurder();
    void builderWeaponMurder();
    void builderHelmetYanLong();
    void builderArmorYanLong();
    void builderWeaponYanLong();
    // 组装
    Arms builderArms();}
  3. 创立 Builder 实现类(这个类次要实现简单对象创立的哪些局部须要什么属性)

    public class ArmsBuilder implements PersonBuilder{
    
        private Arms arms;
    
        public ArmsBuilder() {arms = new Arms();
        }
    
        @Override
        public void builderHelmetMurder() {arms.setHelmet("夺命头盔");
        }
    
        @Override
        public void builderArmorMurder() {arms.setArmor("夺命盔甲");
        }
    
        @Override
        public void builderWeaponMurder() {arms.setWeapon("夺命宝刀");
        }
    
        @Override
        public void builderHelmetYanLong() {arms.setHelmet("炎龙头盔");
        }
    
        @Override
        public void builderArmorYanLong() {arms.setArmor("炎龙铠甲");
        }
    
        @Override
        public void builderWeaponYanLong() {arms.setWeapon("炎龙宝刀");
        }
    
        @Override
        public Arms builderArms() {return arms;}
    }
  4. Director(调用具体建造者来创立简单对象的各个局部,在指导者中不波及具体产品的信息,只负责保障对象各局部残缺创立或按某种程序创立)

    public class PersonDirector {
    /**
     * 组装
     */
    public Arms constructPerson(PersonBuilder pb) {pb.builderHelmetYanLong();
        pb.builderArmorMurder();
        pb.builderWeaponMurder();
        return pb.builderArms();}
    
    /**
     * 开始进行测试
     */
    public static void main(String[] args) {PersonDirector personDirector = new PersonDirector();
        Arms arms = personDirector.constructPerson(new ArmsBuilder());
        System.out.println(arms.getHelmet());
        System.out.println(arms.getArmor());
        System.out.println(arms.getWeapon());
    }

模板办法模式

什么是模板办法

模板办法模式:定义一个操作中的算法骨架(父类),而将一些步骤提早到子类中。模板办法是得子类能够不扭转一个算法的构造来重定义该算法的。

什么时候应用模板办法

实现一些操作时,整体步骤很固定,然而呢。就是其中一小部分须要扭转,这时候能够应用模板办法模式,将容易变的局部形象进去,供子类实现。

理论开发中利用场景哪里用到了模板办法

  1. 其实很多框架中都有用到了模板办法模式
  2. 例如:数据库拜访的封装、Junit 单元测试、servlet 中对于 doGet/doPost 办法的调用等等

现实生活中的模板办法

例如:去餐厅吃饭,餐厅给咱们提供了一个模板就是:看菜单、点菜、吃饭、付款、走人(这里“点菜和付款”是不确定的由子类来实现的,其余的则是一个模板)

代码演示:

  1. 先定义一个模板,把模板中的点菜和付款,让子类来实现。

    /**
     * 模板办法
     */
    public abstract class RestaurantTemplate {
        /**
         * 看菜单
         */
        public void menu() {System.out.println("看菜单");
        }
    
        /**
         * 点菜业务
         */
        abstract void spotMenu();
    
        /**
         * 吃饭业务
         */
        public void havingDinner() {System.out.println("吃饭");
        }
    
        /**
         * 付款业务
         */
        abstract void payment();
    
        /**
         * 走人
         */
        public void GoR() {System.out.println("走人");
        }
    
        /**
         * 模板通用构造
         */
        public void process() {menu();
            spotMenu();
            havingDinner();
            payment();
            GoR();}
    }
  2. 具体的模板办法子类 one

    public class RestaurantLobsterImpl extends RestaurantTemplate{
        /**
         * 点菜业务
         */
        @Override
        void spotMenu() {System.out.println("龙虾");
        }
    
        /**
         * 付款业务
         */
        @Override
        void payment() {System.out.println("50 块");
        }
    }
  3. 具体的模板办法子类 two

    public class RestaurantGinsengImpl extends RestaurantTemplate{
        /**
         * 点菜业务
         */
        @Override
        void spotMenu() {System.out.println("人参");
        }
    
        /**
         * 付款业务
         */
        @Override
        void payment() {System.out.println("5 块");
        }
    }
  4. 客户端测试

    public class Client {public static void main(String[] args) {RestaurantLobsterImpl restaurantLobster = new RestaurantLobsterImpl();
            restaurantLobster.process();}
    }

外观模式

什么是外观模式

  1. 外观模式:也叫门面模式,暗藏零碎的复杂性,并向客户端提供了一个客户端能够拜访零碎的接口。
  2. 它向现有的零碎增加一个接口,用这一个接口来暗藏理论的零碎的复杂性。
  3. 应用外观模式,他内部看起来就是一个接口,其实他的外部有很多简单的接口曾经被实现。

代码演示:

用户注册完之后,须要调用阿里短信接口、邮件接口、微信推送接口。

  1. 创立阿里短信接口

    /**
     * 阿里短信音讯
     */
    public interface AliSmsService {void sendSms();
    }
    public class AliSmsServiceImpl implements AliSmsService{
        @Override
        public void sendSms() {System.out.println("阿里短信音讯");
        }
    }
  2. 创立邮件接口

    /**
     * 发送邮件音讯
     */
    public interface EamilSmsService {void sendSms();
    }
    public class EamilSmsServiceImpl implements EamilSmsService{
        @Override
        public void sendSms() {System.out.println("发送邮件音讯");
        }
    }
  3. 创立微信推送接口

    /**
     * 微信音讯推送
     */
    public interface WeixinSmsService {void sendSms();
    }
    public class WeiXinSmsServiceImpl implements WeixinSmsService{
        @Override
        public void sendSms() {System.out.println("发送微信音讯推送");
        }
    }
  4. 创立门面(门面看起来很简略,简单的货色以及被门面给封装好了)

    public class Computer {
        AliSmsService aliSmsService;
        EamilSmsService eamilSmsService;
        WeixinSmsService weixinSmsService;
    
        public Computer() {aliSmsService = new AliSmsServiceImpl();
            eamilSmsService = new EamilSmsServiceImpl();
            weixinSmsService = new WeiXinSmsServiceImpl();}
    
        /**
         * 只须要调用它
         */
        public void sendMsg() {aliSmsService.sendSms();
            eamilSmsService.sendSms();
            weixinSmsService.sendSms();}
    }
  5. 进行测试

    public class Client {public static void main(String[] args) {new Computer().sendMsg();}
    }

原型模式

什么原型模式

  1. 原型设计模式简略来说就是克隆
  2. 原型表明了有一个样板实例,这个原型是可定制的。原型模型多用于创立简单的或者结构耗时的实例,因为这种状况下,复制一个曾经存在的实例可使程序运行更高效。

原型模式的利用场景

  1. 类初始化须要消化十分多的资源,这个资源包含数据、硬件资源等。这时咱们就能够通过原型拷贝防止这些耗费。
  2. 通过 new 产生的一个对象须要十分繁琐的数据筹备或者权限,这时能够应用原型模式。
  3. 一个对象须要提供给其余对象拜访,而且各个调用者可能都须要批改其值时,能够思考应用原型模式拷贝多个对象供调用者应用,即保护性拷贝。

原型模式的应用形式

  1. 实现 Cloneable 接口。在 java 语言有一个 Cloneable 接口,它的作用只有一个,就是在运行时告诉虚拟机能够平安地在实现了此接口的类上应用 clone 办法。在 java 虚拟机中,只有实现了这个接口的类才能够被拷贝,否则在运行时会抛出 CloneNotSupportedException 异样。
  2. 重写 Object 类中的 clone 办法。Java 中,所有类的父类都是 Object 类,Object 类中有一个 clone 办法,作用是返回对象的一个拷贝,然而其作用域 protected 类型的,个别的类无奈调用,因而 Prototype 类须要将 clone 办法的作用域批改为 public 类型。

正文完
 0