zoukankan      html  css  js  c++  java
  • 工厂设计模式

     

    什么工厂模式

     实现了创建者和调用者分离,工厂模式分为简单工厂、工厂方法、抽象工厂(比较少)模式。

    工厂模式好处

    工厂模式是我们最常用的实例化对象模式了,是用工厂方法代替new操作的一种模式。

    利用工厂模式可以降低程序的耦合性,为后期的维护修改提供了很大的便利。

    将选择实现类、创建对象统一管理和控制。从而将调用者跟我们的实现类解耦。

    工厂模式分类

    简单工厂模式

    简单工厂模式相当于是一个工厂中有各种产品,创建在一个类中,客户无需知道具体产品的名称,只需要知道产品类所对应的参数即可。但是工厂的职责过重,而且当类型过多时不利于系统的扩展维护。

    简单工厂的优点/缺点

    优点:简单工厂模式能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。明确区分了各自的职责和权力,有利于整个软件体系结构的优化。

    缺点:很明显工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则。

    简单工厂代码

    package com.example.demo.factory;

    /**
    * 接口
    */
    public interface Car {

    void run();
    }
    package com.example.demo.factory;

    /**
    * 实现类
    */
    public class BaoMa implements Car {
    @Override
    public void run() {
    System.out.println("宝马车...");
    }
    }
    package com.example.demo.factory;

    /**
    * 实现类
    */
    public class BenChi implements Car {
    @Override
    public void run() {
    System.out.println("奔驰车...");
    }
    }
    package com.example.demo.factory;

    /**
    * 简单工厂 如果判断比较多的话 后期不利于维护
    */
    public class CarFactory {
    public static Car createCar(String name) {
    if (name == null || name == "") {
    return null;
    }
    if (name.equals("宝马")) {
    return new BaoMa();
    }
    if (name.equals("奔驰")) {
    return new BenChi();
    }

    return null;
    }
    }
    package com.example.demo.factory;

    public class Client {
    public static void main(String[] args) {
    // new 创建对象的 调用方法
    // Car benChi=new BenChi();
    // Car baoMa = new BaoMa();
    //
    // benChi.run();
    // baoMa.run();

    //简单工厂的调用方法
    Car car = CarFactory.createCar("宝马");
    car.run();
    }
    }

    工厂方法模式

    什么是工厂方法模式

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

    package com.example.demo.factory02;

    /**
    * 接口
    */
    public interface Car {

    void run();
    }
    package com.example.demo.factory02;

    /**
    * 实现类
    */
    public class BaoMa implements Car {
    @Override
    public void run() {
    System.out.println("宝马车...");
    }
    }
    package com.example.demo.factory02;

    /**
    * 实现类
    */
    public class BenChi implements Car {
    @Override
    public void run() {
    System.out.println("奔驰车...");
    }
    }
    package com.example.demo.factory02;

    /**
    * 工厂方法模式
    */
    public interface CarFactory {
    Car createCar(String name);

    }
    package com.example.demo.factory02;

    /**
    * 奔驰汽车工厂
    */
    public class BenChiFactory implements CarFactory {

    @Override
    public Car createCar(String name) {
    System.out.println("奔驰汽车...");
    return new BenChi();
    }
    }
    package com.example.demo.factory02;

    /**
    * 宝马汽车工厂
    */
    public class BaoMaFactory implements CarFactory {

    @Override
    public Car createCar(String name) {

    System.out.println("宝马汽车...");
    return new BaoMa();
    }
    }
    package com.example.demo.factory02;

    public class Client {
    public static void main(String[] args) {
    // new 创建对象的 调用方法
    // Car benChi=new BenChi();
    // Car baoMa = new BaoMa();
    //
    // benChi.run();
    // baoMa.run();

    //工厂方法
    BaoMaFactory baoMaFactory=new BaoMaFactory();
    Car car = baoMaFactory.createCar("宝马");
    car.run();

    BenChiFactory benChiFactory=new BenChiFactory();
    Car car1 = benChiFactory.createCar("奔驰");
    car1.run();
    }
    }

    抽象工厂模式

    什么抽象工厂模式

    抽象工厂简单地说是工厂的工厂,抽象工厂可以创建具体工厂,由具体工厂来产生具体产品。

    抽象工厂代码:

    package com.example.demo.factory03;

    /**
    * 包装 组件
    */
    public interface Factory {

    /**
    * 创建发动机
    */
    Engine createEngine();

    /**
    * 创建座椅
    * @return
    */
    Chair createChair();
    }
    package com.example.demo.factory03;

    /**
    * 发动机 组件
    */
    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("发动机转速慢");
    }
    }
    package com.example.demo.factory03;

    /**
    * 座椅 组件
    */
    public interface Chair {
    void run();
    }

    class ChairA implements Chair{

    @Override
    public void run() {
    System.out.println("带加热功能的座椅");
    }
    }



    class ChairB implements Chair{

    @Override
    public void run() {
    System.out.println("不带加热功能的座椅");
    }
    }
    package com.example.demo.factory03;

    /**
    * 宝马工厂
    */
    public class BaoMaFactory implements Factory {

    @Override
    public Engine createEngine() {
    return new EngineA();
    }

    @Override
    public Chair createChair() {
    return new ChairB();
    }
    }
    package com.example.demo.factory03;

    public class Client {
    public static void main(String[] args) {
    Factory baoMaFactory = new BaoMaFactory();
    Chair chair = baoMaFactory.createChair();
    Engine engine = baoMaFactory.createEngine();
    chair.run();
    engine.run();

    }
    }

    简单工厂、工厂方法、抽象工厂之小结、区别

    简单工厂 : 用来生产同一等级结构中的任意产品。(不支持拓展增加产品)

    工厂方法 :用来生产同一等级结构中的固定产品。(支持拓展增加产品)   

    抽象工厂 :用来生产不同产品族的全部产品。(不支持拓展增加产品;支持增加产品族,例如车轮胎、车玻璃、车座椅等产品类型)

    代理模式

    什么代理模式

    通过代理控制对象的访问,可以详细访问某个对象的方法,在这个方法调用之前或调用后进行处理。既(AOP微实现)  ,AOP核心技术面向切面编程。

    代理模式应用场景

    SpringAOP、事物原理、日志打印、权限控制、远程调用、安全代理 可以隐蔽真实角色

    代理分类

    静态代理(静态定义代理类)

    动态代理(动态生成代理类)

    Jdk自带动态代理

    Cglib 、javaassist(字节码操作库)

    静态代理

    什么是静态代理

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

    静态代理代码:

    package com.example.demo.factory04;

    /**
    * 接口
    */
    public interface UserDao {
    void add();
    }
    package com.example.demo.factory04;

    /**
    * 接口实现类
    */
    public class UserDaoImpl implements UserDao {
    @Override
    public void add() {

    System.out.println("执行新增操作...");

    }
    }
    package com.example.demo.factory04;

    /**
    * 静态代理
    */
    public class UserDaoProxy implements UserDao {

    private UserDao userDao;

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

    }
    @Override
    public void add() {
    System.out.println("开启事务...");
    userDao.add();
    System.out.println("提交事务...");
    }
    }
    package com.example.demo.factory04;

    /**
    * 静态代理 静态需要生成代理对象
    * 缺点:需要生成代理对象,如果后期有多个接口处理的话 需要生成多个代理对象 不利于扩展
    */
    public class UserDemo {
    public static void main(String[] args) {
    UserDao userDao=new UserDaoImpl();
    UserDaoProxy userDaoProxy=new UserDaoProxy(userDao);
    userDaoProxy.add();
    }
    }

    动态代理

    什么是动态代理

    1.代理对象,不需要实现接口

    2.代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)

    3.动态代理也叫做:JDK代理,接口代理

    JDK动态代理

     原理:是根据类加载器和接口创建代理类(此代理类是接口的实现类,所以必须使用接口 面向接口生成代理,位于java.lang.reflect包下)

     实现方式:

    1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);

    2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});

    3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});

    4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));

    缺点:jdk动态代理,必须是面向接口,目标业务类必须实现接口

    jdk动态代理代码:

    package com.example.demo.factory05;

    import com.example.demo.factory04.UserDao;
    import com.example.demo.factory04.UserDaoImpl;

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;

    /**
    * JDK 动态代理对象
    * 每次生成动态代理对象时,实现了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("动态代理开启事务");
    Object invoke = method.invoke(target, args);
    System.out.println("动态代理提交事务");
    return invoke;
    }

    public static void main(String[] args) {
    //被代理对象
    UserDao userDao=new UserDaoImpl();
    InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userDao);
    //获取类加载器
    ClassLoader classLoader = userDao.getClass().getClassLoader();
    //获取当前实现的接口信息
    Class<?>[] interfaces = userDao.getClass().getInterfaces();

    //调用动态代理实例 主装载器、一组接口及调用处理动态代理实例
    UserDao userDao1 = (UserDao) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    userDao1.add();
    }
    }

    CGLIB动态代理

    原理:利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。 

    什么是CGLIB动态代理

    使用cglib[Code Generation Library]实现动态代理,并不要求委托类必须实现接口,底层采用asm字节码生成框架生成代理类的字节码。

    CGLIB代码:

    package com.example.demo.cglibproxy;


    import com.example.demo.factory04.UserDao;
    import com.example.demo.factory04.UserDaoImpl;
    import org.springframework.cglib.proxy.Enhancer;
    import org.springframework.cglib.proxy.MethodInterceptor;
    import org.springframework.cglib.proxy.MethodProxy;

    import java.lang.reflect.Method;

    /**
    * CGLIB 没有接口依赖关系 底层使用字节码技术 asm
    * JDK 依赖接口 因为底层使用了反射机制
    */
    public class CglibProxy implements MethodInterceptor {

    /**
    * 目标对象
    */
    private Object targetObject;

    public Object getInstance(Object targetObject){
    this.targetObject=targetObject;
    //操作字节码 生成一个虚拟子类
    Enhancer enhancer = new Enhancer();
    enhancer.setSuperclass(targetObject.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 invoke = methodProxy.invoke(targetObject, objects);
    System.out.println("提交事务");
    return invoke;
    }

    /**
    * 如何判断一个类是否实现类接口?通过反射机制
    * @param args
    */
    public static void main(String[] args) {
    CglibProxy cglibProxy = new CglibProxy();
    UserDao instance = (UserDao) cglibProxy.getInstance(new UserDaoImpl());
    instance.add();
    }
    }

    CGLIB动态代理与JDK动态区别

    java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。

    而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

    在Spring中。

    1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP

    2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP

    3、如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换

    JDK动态代理只能对实现了接口的类生成代理,而不能针对类 。
    CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 。
    因为是继承,所以该类或方法最好不要声明成final ,final可以阻止继承和多态。

  • 相关阅读:
    【网易官方】极客战记(codecombat)攻略-地牢-循环又循环
    【网易官方】极客战记(codecombat)攻略-地牢-焰中舞动
    【网易官方】极客战记(codecombat)攻略-地牢-祸之火焰
    【网易官方】极客战记(codecombat)攻略-地牢-囚犯
    【网易官方】极客战记(codecombat)攻略-地牢-高举之剑
    【网易官方】极客战记(codecombat)攻略-地牢-Kithgard 图书管理员
    【网易官方】极客战记(codecombat)攻略-地牢-注释中的密语
    【网易官方】极客战记(codecombat)攻略-地牢-机会有利
    linux 系统调用之文件操作
    linux系统调用之进程控制
  • 原文地址:https://www.cnblogs.com/ming-blogs/p/10829213.html
Copyright © 2011-2022 走看看