Шаблоны проектирования | Шаблоны внешнего вида и типичные приложения

Java задняя часть Шаблоны проектирования Tomcat

предисловие

Основное содержание этой статьи:

  • Представляем режим внешнего вида
  • Пример
    • сделать свой собственный чай
    • Сходить в чайхану на чай
  • Сводка режима внешнего вида
  • Типичные применения внешнего вида
    • Режим внешнего вида в Spring JDBC
    • Внешний вид в Mybatis
    • Фасадный режим в Tomcat
    • Фасадный режим в SLF4J

Внешний вид Режим

Шаблон фасада — это очень часто используемый шаблон структурного проектирования.Он упрощает взаимодействие между клиентами и подсистемами за счет введения роли фасада, обеспечивает унифицированный вход для сложных вызовов подсистемы и снижает сложность подсистем и клиентов.Конечная степень связанности, и звонок клиента очень удобен.

Режим фасада, также известный как режим фасада, является объектно-структурированным режимом. Режим внешнего вида - это особая реализация закона Демететера. Представляя новую роль внешнего вида, сложность исходной системы может быть уменьшена, а соединение между классами клиента и подсистемами может быть уменьшена.

Режим внешнего вида включает следующие две роли:

Фасад (фасадный персонаж): его методы могут быть вызваны на стороне клиента, а функции и обязанности соответствующей подсистемы (подсистем) могут быть известны в роли фасада; при нормальных обстоятельствах он делегирует все запросы от клиента соответствующей подсистеме, он передается соответствующему объекту подсистемы для обработки.

SubSystem (роль подсистемы): В программной системе может быть одна или несколько ролей подсистем, каждая подсистема может быть не отдельным классом, а набором классов, реализующим функции подсистем; каждая подсистема может вызываться непосредственно клиентом или вызываться роль внешнего вида, которая обрабатывает запросы от класса внешнего вида, подсистема не знает о существовании внешнего вида, и для подсистемы роль внешнего вида является просто еще одним клиентом.

Целью шаблона внешнего вида является не добавление новых функциональных интерфейсов в подсистему, а сокращение внешнего взаимодействия с несколькими модулями в подсистеме и их слабое связывание, чтобы внешний мог легче использовать подсистему.

Суть режима внешнего вида заключается в следующем:Инкапсулируйте взаимодействия и упростите вызовы.

Пример

Чай нуждается в водеWater

public class Water {
    private int temperature;    // 温度
    private int capacity;       // 容量
    public Water() {
        this.temperature = 0;
        this.capacity = 10;
    }
    // 省略...
}    

Для чая нужны чайные листьяTeaLeaf

public class TeaLeaf {
    private String teaName;
    // 省略...
}    

Вам нужно использовать чайник, чтобы вскипятить воду, чтобы нагреть воду

public class KettleService {
    public void waterBurning(String who, Water water, int burnTime) {
        // 烧水,计算最终温度
        int finalTermperature = Math.min(100, water.getTemperature() + burnTime * 20);
        water.setTemperature(finalTermperature);
        System.out.println(who + " 使用水壶烧水,最终水温为 " + finalTermperature);
    }
}

Заварите чай, заварите кипяток и заварку и, наконец, получите чашку чая.

public class TeasetService {
    public Teawater makeTeaWater(String who, Water water, TeaLeaf teaLeaf) {
        String teawater = "一杯容量为 " + water.getCapacity() + ", 温度为 " + water.getTemperature() + " 的" + teaLeaf.getTeaName() + "茶水";
        System.out.println(who + " 泡了" + teawater);
        return new Teawater(teawater);
    }
}

мужчина пьет чай

public class Man {
    private String name;
    public Man(String name) {
        this.name = name;
    }
    public void drink(Teawater teawater) {
        System.out.println(name + " 喝了" + teawater.getTeaWater());
    }
}

сделать свой собственный чай

Чжан Сан и Ли Си заваривают чай и пьют, и каждому нужно приготовить чайные сервизы, чайные листья и воду, а также выполнять такие операции, как кипячение воды и приготовление чая.

public class Main {
    public static void main(String[] args) {
        Man zhangsan = new Man("张三");
        KettleService kettleService1 = new KettleService();
        TeasetService teasetService1 = new TeasetService();
        Water water1 = new Water();
        TeaLeaf teaLeaf1 = new TeaLeaf("西湖龙井");
        kettleService1.waterBurning(zhangsan.getName(), water1, 4);
        Teawater teawater1 = teasetService1.makeTeaWater(zhangsan.getName(), water1, teaLeaf1);
        zhangsan.drink(teawater1);
        System.out.println();

        Man lisi = new Man("李四");
        KettleService kettleService2 = new KettleService();
        TeasetService teasetService2 = new TeasetService();
        Water water2 = new Water(10, 15);
        TeaLeaf teaLeaf2 = new TeaLeaf("碧螺春");
        kettleService2.waterBurning(lisi.getName(), water2, 4);
        Teawater teawater2 = teasetService2.makeTeaWater(lisi.getName(), water2, teaLeaf2);
        lisi.drink(teawater2);
    }
}

Выход

张三 使用水壶烧水,最终水温为 80
张三 泡了一杯容量为 10, 温度为 80 的西湖龙井茶水
张三 喝了一杯容量为 10, 温度为 80 的西湖龙井茶水

李四 使用水壶烧水,最终水温为 90
李四 泡了一杯容量为 15, 温度为 90 的碧螺春茶水
李四 喝了一杯容量为 15, 温度为 90 的碧螺春茶水

Заварите себе чай и пейте

自己泡茶喝模式图

Сходить в чайхану на чай

Чайный домик, чайный домик имеет разные пакеты

public class TeaHouseFacade {
    private String name;
    private TeasetService teasetService;
    private KettleService kettleService;

    public TeaHouseFacade(String name) {
        this.name = name;
        this.teasetService = new TeasetService();
        this.kettleService = new KettleService();
    }

    public Teawater makeTea(int teaNumber) {
        switch (teaNumber) {
            case 1:
                Water water1 = new Water();
                TeaLeaf teaLeaf1 = new TeaLeaf("西湖龙井");
                kettleService.waterBurning(this.name, water1, 4);
                Teawater teawater1 = teasetService.makeTeaWater(this.name, water1, teaLeaf1);
                return teawater1;
            case 2:
                Water water2 = new Water(10, 15);
                TeaLeaf teaLeaf2 = new TeaLeaf("碧螺春");
                kettleService.waterBurning(this.name, water2, 4);
                Teawater teawater2 = teasetService.makeTeaWater(this.name, water2, teaLeaf2);
                return teawater2;
            default:
                Water water3 = new Water();
                TeaLeaf teaLeaf3 = new TeaLeaf("招牌乌龙");
                kettleService.waterBurning(this.name, water3, 5);
                Teawater teawater3 = teasetService.makeTeaWater(this.name, water3, teaLeaf3);
                return teawater3;
        }
    }
}

Чжан Сан и Ли заказывают чай в четыре, просто сообщите номер упаковки чайханы, вода и чайные листья готовятся чайханой, а операция кипячения воды для приготовления чая выполняется чайханой равномерно.

public class Test {
    public static void main(String[] args) {
        TeaHouseFacade teaHouseFacade = new TeaHouseFacade("老舍茶馆");

        Man zhangsan = new Man("张三");
        Teawater teawater = teaHouseFacade.makeTea(1);
        zhangsan.drink(teawater);
        System.out.println();

        Man lisi = new Man("李四");
        Teawater teawater1 = teaHouseFacade.makeTea(2);
        lisi.drink(teawater1);
    }
}

Выход

老舍茶馆 使用水壶烧水,最终水温为 80
老舍茶馆 泡了一杯容量为 10, 温度为 80 的西湖龙井茶水
张三 喝了一杯容量为 10, 温度为 80 的西湖龙井茶水

老舍茶馆 使用水壶烧水,最终水温为 90
老舍茶馆 泡了一杯容量为 15, 温度为 90 的碧螺春茶水
李四 喝了一杯容量为 15, 温度为 90 的碧螺春茶水

Идите в чайхану, чтобы выпить схему схемы чая

到茶馆喝茶模式图

Сводка режима внешнего вида

режим появленияглавное преимуществоследующее:

  • Он защищает компоненты подсистемы от клиента, уменьшает количество объектов, которые должен обрабатывать клиент, и упрощает использование подсистемы. Благодаря внедрению шаблона Facade код на стороне клиента будет простым, и с ним будет связано несколько объектов.
  • Он реализует слабую связь между подсистемой и клиентом, благодаря чему изменение подсистемы не повлияет на клиент, вызывающий ее, нужно только настроить класс внешнего вида.
  • Модификации одной подсистемы не влияют на другие подсистемы, а изменения внутри подсистем не влияют на объекты внешнего вида.

режим появленияглавный недостатокследующее:

  • Не очень хорошо запрещать клиентам прямое использование классов подсистем, и если на клиентов накладывается слишком много ограничений на доступ к классам подсистем, это снижает изменчивость и гибкость.
  • При неправильном проектировании добавление новых подсистем может потребовать изменения исходного кода класса фасада, нарушая принцип открытого-закрытого.

Применимая сцена:

  • Фасадный режим можно использовать, когда вы хотите предоставить простую точку входа для доступа к сложному набору подсистем.
  • Между клиентскими программами и несколькими подсистемами существуют сильные зависимости. Введение фасадного класса может отделить подсистему от клиента, тем самым повысив независимость и переносимость подсистемы.
  • В иерархической структуре режим внешнего вида может использоваться для определения входа каждого слоя в систему.Связь между слоями напрямую не связана, но связь устанавливается через классы внешнего вида, что снижает степень связанности между слоями.

Типичное применение режима внешнего вида анализа исходного кода

Фасадный режим весной jdbc

Проверятьorg.springframework.jdbc.support.JdbcUtils

public abstract class JdbcUtils {
    public static void closeConnection(Connection con) {
		if (con != null) {
			try {
				con.close();
			}
			catch (SQLException ex) {
				logger.debug("Could not close JDBC Connection", ex);
			}
			catch (Throwable ex) {
				// We don't trust the JDBC driver: It might throw RuntimeException or Error.
				logger.debug("Unexpected exception on closing JDBC Connection", ex);
			}
		}
	}
	
	public static Object getResultSetValue(ResultSet rs, int index, Class<?> requiredType) throws SQLException {
		if (requiredType == null) {
			return getResultSetValue(rs, index);
		}

		Object value = null;
		boolean wasNullCheck = false;

		// Explicitly extract typed value, as far as possible.
		if (String.class.equals(requiredType)) {
			value = rs.getString(index);
		}
		else if (boolean.class.equals(requiredType) || Boolean.class.equals(requiredType)) {
			value = rs.getBoolean(index);
			wasNullCheck = true;
		}
		else if (byte.class.equals(requiredType) || Byte.class.equals(requiredType)) {
			value = rs.getByte(index);
			wasNullCheck = true;
		}
		else if (short.class.equals(requiredType) || Short.class.equals(requiredType)) {
			value = rs.getShort(index);
			wasNullCheck = true;
		}
		else if (int.class.equals(requiredType) || Integer.class.equals(requiredType)) {
			value = rs.getInt(index);
			wasNullCheck = true;
		}
		else if (long.class.equals(requiredType) || Long.class.equals(requiredType)) {
			value = rs.getLong(index);
			wasNullCheck = true;
		}
		else if (float.class.equals(requiredType) || Float.class.equals(requiredType)) {
			value = rs.getFloat(index);
			wasNullCheck = true;
		}
		else if (double.class.equals(requiredType) || Double.class.equals(requiredType) ||
				Number.class.equals(requiredType)) {
			value = rs.getDouble(index);
			wasNullCheck = true;
		}
		else if (byte[].class.equals(requiredType)) {
			value = rs.getBytes(index);
		}
		else if (java.sql.Date.class.equals(requiredType)) {
			value = rs.getDate(index);
		}
		else if (java.sql.Time.class.equals(requiredType)) {
			value = rs.getTime(index);
		}
		else if (java.sql.Timestamp.class.equals(requiredType) || java.util.Date.class.equals(requiredType)) {
			value = rs.getTimestamp(index);
		}
		else if (BigDecimal.class.equals(requiredType)) {
			value = rs.getBigDecimal(index);
		}
		else if (Blob.class.equals(requiredType)) {
			value = rs.getBlob(index);
		}
		else if (Clob.class.equals(requiredType)) {
			value = rs.getClob(index);
		}
		else {
			// Some unknown type desired -> rely on getObject.
			value = getResultSetValue(rs, index);
		}
		
		if (wasNullCheck && value != null && rs.wasNull()) {
			value = null;
		}
		return value;
	}
    // ...省略...
}    

Этот класс инструментов в основном инкапсулирует собственный JDBC.

Внешний вид в Mybatis

Проверятьorg.apache.ibatis.session.Configurationкласс сnewспособ начать

public class Configuration {
	public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
	    executorType = executorType == null ? defaultExecutorType : executorType;
	    executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
	    Executor executor;
	    if (ExecutorType.BATCH == executorType) {
	      executor = new BatchExecutor(this, transaction);
	    } else if (ExecutorType.REUSE == executorType) {
	      executor = new ReuseExecutor(this, transaction);
	    } else {
	      executor = new SimpleExecutor(this, transaction);
	    }
	    if (cacheEnabled) {
	      executor = new CachingExecutor(executor);
	    }
	    executor = (Executor) interceptorChain.pluginAll(executor);
	    return executor;
	}
	
	public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler,
	      ResultHandler resultHandler, BoundSql boundSql) {
	    ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds);
	    resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
	    return resultSetHandler;
	}
	// ...省略...
}

Этот класс в основном инкапсулирует некоторые операции по созданию объектов.

Фасадный режим в Tomcat

Исходный код Tomcat активно использует множество режимов скинов

Tomcat中的外观模式

org.apache.catalina.connector.Requestиorg.apache.catalina.connector.RequestFacadeОба класса реализуютHttpServletRequestинтерфейс

существуетRequestвызыватьgetRequest()То, что получается на самом деле,RequestFacadeОбъект

protected RequestFacade facade = null;

public HttpServletRequest getRequest() {
    if (facade == null) {
        facade = new RequestFacade(this);
    }
    return facade;
}

существуетRequestFacadeСнова упаковать работу подсистемы

public class RequestFacade implements HttpServletRequest {
    /**
     * The wrapped request.
     */
    protected Request request = null;
    
    @Override
    public Object getAttribute(String name) {
        if (request == null) {
            throw new IllegalStateException(sm.getString("requestFacade.nullRequest"));
        }
        return request.getAttribute(name);
    }
    // ...省略...
}    

Фасадный режим в SLF4J

SLF4J— это простая структура шаблона внешнего вида журнала, которая абстрагирует различные структуры журнала, такие какLogback,Log4j,Commons-loggingиJDKавтономныйloggingРеализовать интерфейс. Это позволяет пользователям использовать структуру ведения журналов в нужное время развертывания.

SLF4J не заменяет никакую структуру ведения журнала, это просто шаблон фасада для стандартной структуры ведения журнала.. Если в пути к классам, кромеSLF4JБез какой-либо структуры ведения журналов по умолчанию журналы выводятся на консоль.

Фреймворк обработки журналов Logback является улучшенной версией Log4j и изначально поддерживает SLF4J (поскольку он был разработан тем же автором), поэтому комбинация Logback+SLF4J — лучший выбор для каркаса журналирования, который быстрее, чем комбинация SLF4J. +другие фреймворки для журналирования. И конфигурация Logback может быть XML или кодом Groovy.

Приветственный мир SLF4J выглядит следующим образом:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class HelloWorld {
  public static void main(String[] args) {
    Logger logger = LoggerFactory.getLogger(HelloWorld.class);
    logger.info("Hello World");
  }
}

На следующем рисунке показаны отношения вызова привязки между SLF4J и платформой обработки журналов.

SLF4J与日志处理框架的绑定调用关系

Вызов прикладного уровняslf4j-api.jar,slf4j-api.jarЗатем вызовите различные пакеты jar для обработки в соответствии с привязанной структурой обработки журналов.

Ссылаться на:
Лю Вэй: Шаблоны проектирования Java Edition
MOOC Java Design Patterns Интенсивный метод отладки + анализ памяти
Фреймворк логирования Java: роль slf4j и принцип ее реализации

Рекомендуемое чтение

Шаблоны проектирования | Простые фабричные шаблоны и типовые приложения
Шаблоны проектирования | Шаблоны фабричных методов и типичные приложения
Шаблоны проектирования | Абстрактные фабричные шаблоны и типовые приложения
Шаблоны проектирования | Шаблоны построителей и типичные приложения
Шаблоны проектирования | Шаблоны прототипов и типовые приложения

Нажмите [читать оригинал], чтобы посетить мой личный блог:laijianfeng.org

关注【小旋锋】微信公众号