Интерфейс, предоставляемый SDK, неразумен.
Мы часто используем некоторые SDK для удовлетворения наших потребностей, но интерфейсы, предоставляемые некоторыми SDK, часто неразумны.Кроме того, если сам SDK находится в периоде быстрой итерации, каждый раз, когда некоторые API-интерфейсы изменяются, бизнес-сторона будет использовать больше. их много, тогда пакетная модификация на самом деле более хлопотна.
Посмотрите, как сделать некоторые улучшения для вышеперечисленного
Взгляните на пример кода:
public class SchoolSystemSdk {
/**
* 存储学生
*
* @param name 姓名
* @param age 年纪
* @param No 学号
*/
public void saveStudent(String name, int age, int No) {
}
/**
* 存储教师
*
* @param name 教师姓名
* @param studentNumber 学生数量
* @param schoolName 学校名称
*/
public void saveTeacher(String name, int studentNumber, String schoolName) {
}
}
public class TestMain {
public static void main(String[] args) {
SchoolSystemSdk schoolSystemSdk=new SchoolSystemSdk();
schoolSystemSdk.saveStudent("wuyue",18,12345);
schoolSystemSdk.saveTeacher("wuyanzu",18,"南京大学");
}
}
Проблема в том, что sdk предоставляет слишком много параметров функций извне, а инкапсуляция отсутствует, и легко подумать, что если sdk в будущем добавит новые параметры, то наш бизнес-код придется модифицировать пачками, что очень болезненно. Но у нас нет разрешения на изменение исходного кода sdk (пока технологии байт-кода, такие как asm, не рассматриваются)
Внесите следующие изменения: Сначала определите учеников и учителей
class Student {
String name;
int age;
int No;
}
class Teacher {
String name;
int studentNumber;
String schoolName;
}
Определите другой интерфейс, обратите внимание на параметры интерфейса
public interface ISchoolSystem {
void saveStudent(Student student);
void saveTeacher(Teacher teacher);
}
Затем определите наш основной класс. Обратите внимание на объявление класса.
//extends了sdk的类 且实现了接口
public class SchoolSystemWrapper extends SchoolSystemSdk implements ISchoolSystem {
@Override
public void saveStudent(Student student) {
saveStudent(student.name, student.age, student.No);
}
@Override
public void saveTeacher(Teacher teacher) {
//懒癌发作 就此省略
}
}
последний звонок
public class TestMain {
public static void main(String[] args) {
ISchoolSystem iSchoolSystem = new SchoolSystemWrapper();
//懒癌发作 这边构造函数 就没有传参了,大家自行领会意图
iSchoolSystem.saveStudent(new Student());
iSchoolSystem.saveTeacher(new Teacher());
}
}
Несколько простых шагов могут решить все наши болевые точки. Это необходимо для решения проблемы, связанной с тем, что собственный SDK предоставляет внешнему миру неверные параметры функции, а также может решить проблему множественных модификаций при обновлении SDK в будущем.
Единое управление сторонними SDK с аналогичными функциями
Этот сценарий не редкость в бизнесе.Например, нам нужно использовать разные сторонние SDK для обработки определенных требований.Мы надеемся собрать интерфейсы этих разных сторонних SDK, а затем выставить простой интерфейс для внешнего мира.
Например: для фрагмента текста нам нужно отфильтровать желтую информацию, информацию, не подходящую для детей, и информацию, которая не соответствует политикам и правилам. Давайте посмотрим, как должен быть написан этот код:
//过滤掉不良的黄色信息
public class AWordsFilter {
public String filterSexyWords(String text) {
return "";
}
}
//过滤掉政治信息
class BWordsFilter {
public String filterPoliticalWords(String text) {
return "";
}
}
//过滤掉工信部给的敏感信息 senseWords 为敏感词
class CWordsFilter {
public String filterSenselWords(String text, String senseWords) {
return "";
}
}
использовать его
public class TestMain {
public static void main(String[] args) {
//原始文本
String text = "1231231asdasdasdasda";
//三种过滤规则
AWordsFilter aWordsFilter = new AWordsFilter();
BWordsFilter bWordsFilter = new BWordsFilter();
CWordsFilter cWordsFilter = new CWordsFilter();
//过滤成最终想要的信息
String t1 = aWordsFilter.filterSexyWords(text);
String t2 = bWordsFilter.filterPoliticalWords(t1);
String t3 = cWordsFilter.filterSenselWords(t2, "蛤蛤");
}
}
Начать оптимизацию кода Сначала определите 2 интерфейса:
public interface IWordsFilter {
String filter(String text);
}
public interface IWordsSenseFilter extends IWordsFilter {
String filter(String text, String sense);
}
Затем для их реализации:
public class AWordsFilterAdaptor implements IWordsFilter {
AWordsFilter aWordsFilter;
@Override
public String filter(String text) {
return aWordsFilter.filterSexyWords(text);
}
}
class BWordsFilterAdaptor implements IWordsFilter {
BWordsFilter bWordsFilter;
@Override
public String filter(String text) {
return bWordsFilter.filterPoliticalWords(text);
}
}
class CWordsFilterAdaptor implements IWordsSenseFilter {
CWordsFilter cWordsFilter;
@Override
public String filter(String text, String sense) {
return cWordsFilter.filterSenselWords(text, sense);
}
@Override
public String filter(String text) {
return null;
}
}
Окончательное единое управление
class FilterManager {
List<IWordsFilter> filters = new ArrayList<>();
public void addFilterType(IWordsFilter iWordsFilter) {
filters.add(iWordsFilter);
}
public String filterAll(String text, String sense) {
String maskText = text;
for (IWordsFilter iWordsFilter : filters) {
if (iWordsFilter instanceof IWordsSenseFilter) {
maskText = ((IWordsSenseFilter) iWordsFilter).filter(maskText, sense);
} else {
maskText = iWordsFilter.filter(text);
}
}
return maskText;
}
}
Взгляните на эффект использования, может ли он добиться эффекта усадки
String text = "1231231asdasdasdasda";
FilterManager filterManager=new FilterManager();
filterManager.addFilterType(new AWordsFilterAdaptor());
filterManager.addFilterType(new BWordsFilterAdaptor());
filterManager.addFilterType(new CWordsFilterAdaptor());
filterManager.filterAll(text,"蛤蛤");
Здесь следует понимать, что этот режим адаптера особенно подходит для следующих сценариев:Стратегия исправления постфактум, вы не можете контролировать качество кода sdk, или хотя это не код sdk, в старом коде много ям, и изменить его на какое-то время будет непросто, но вы можете использовать этот адаптер, чтобы скорректировать свои цели в области качества кода.
Как отделить нефункциональные требования от бизнес-кода
При нормальной разработке мы часто должны сталкиваться с похожими требованиями, например, предъявлять какие-то требования, но для этих требований нам необходимо выполнять мониторинг, ведение журнала, отслеживание, статистику, аутентификацию и т. д. Разработка этих вещей, по сути, такая же, как и наш бизнес. разработки разделены, и их код не должен быть написан вместе. Итак, как сделать разделение? Вот пример
Предположим, у нас есть функция входа пользователя здесь
public class UserController {
public void login() {
}
public void register() {
}
}
Теперь требуется выполнить некоторый мониторинг этого входа и регистрации, например, записать время начала действий входа и регистрации, записать идентификатор пользователя и так далее. Запись этих кодов непосредственно в наш собственный бизнес входа и регистрации чрезвычайно неэлегантна и сложна в обслуживании.
Если мы ленивы и не хотим изменять исходный код нашего UserController, тогда используйте extends
class UserControllerProxy extends UserController
{
@Override
public void login() {
//在这里做一些监控的操作 代码省略
super.login();
}
@Override
public void register() {
//在这里做一些监控的操作 代码省略
super.register();
}
}
Будьте внимательны, вы можете определить интерфейс, чтобы сделать это
public class UserController implements IUserCon {
public void login() {
}
public void register() {
}
}
interface IUserCon {
void login();
void register();
}
//数据统计
class DataStatic {
public void doSome() {
}
}
class UserControllerProxy implements IUserCon {
public UserControllerProxy(IUserCon iUserCon) {
this.iUserCon = iUserCon;
}
private IUserCon iUserCon;
private DataStatic dataStatic = new DataStatic();
@Override
public void login() {
//在这里做一些监控的操作 代码省略
dataStatic.doSome();
iUserCon.login();
}
@Override
public void register() {
//在这里做一些监控的操作 代码省略
dataStatic.doSome();
iUserCon.register();
}
}
На этом не закончилось, есть другая ситуация, то есть, если есть много методов страницы класса, которые проксируются нами, было бы действительно глупо, если бы мы использовали вышеуказанный метод, чтобы сделать прокси, потому что у вас много повторяющегося кода для писать по-разному в функции. Это опять копипаст.
Кроме того, вы думаете, если у вас больше потребностей в скрытых точках или классах мониторинга, то есть много классов, которые проксируются, не только вход и регистрация, но и другие модули, которые нужно использовать, вы хотите вручную добавить больше класса Proxy ? Если методы захоронения точек когда-нибудь изменятся, сколько мест вы хотите изменить?
Решить эту проблему тоже очень просто
Динамический прокси Генерируйте наш класс динамически и динамически изменяйте код в прокси.
public class UserDynamicProxy implements InvocationHandler {
DataStatic dataStatic;
public UserDynamicProxy(Object target) {
this.target = target;
dataStatic = new DataStatic();
}
Object target;
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
dataStatic.doSome();
Object result = method.invoke(target, args);
return result;
}
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
}
Это также проще в использовании
UserDynamicProxy dynamicProxy = new UserDynamicProxy(new UserController());
IUserCon iUserCon = dynamicProxy.getProxy();
iUserCon.register();
Если вам посчастливилось удовлетворить такой спрос в своем проекте, вы можете использовать динамический прокси, мощные функции и минималистский текст. В этой статье мы не будем подробно рассказывать об этом принципе. Не в центре внимания этой статьи. Заинтересованные могут увидетьПринцип динамического прокси
Последний, но тем не менее важный: Агентная модель обычно используется в бизнес-системах.Разработать некоторые нефункциональные требования, такие как: мониторинг, статистика, аутентификация, ограничение тока, скрытые точки, журналы. мы будем этимДополнительные функции отделены от бизнес-функций и помещены в прокси-класс для унифицированной обработки., так что студенты развития бизнеса обращают внимание только на бизнес и не должны обращать внимание на основные функции.Не изменяя интерфейс исходного класса, определите прокси-класс для исходного класса, основной целью которого является управление доступом, а не улучшение функции.
Философия дизайна в java IO
Java IO может быть самым сложным модулем в системе Java.Он часто используется, но мало кто может разобраться в этом дизайне.Сегодня у нас есть скин, посмотрим чему можно научиться
Сначала посмотрите на старую картину, это должно быть знакомым для многих людей
Теперь мы пытаемся прочитать файл, для повышения эффективности мы используем кеш-буфер.
InputStream in=new FileInputStream("F:\\Java huashan.pdf");
InputStream bin=new BufferedInputStream(in);
Вы заметили разницу в этом письме? Почему вы должны использовать inputStream для инициализации буферов?Почему файлы могут быть созданы путем прямой передачи пути, но не буферов?
Конструктор буферинов:
Взгляните на конструктор файлов
Итак, вот наступает вопрос, почему конструктор класса Bufferins занимается параметром и не может быть установлен непосредственно похожи на файлы, Напрямую принимайте путь в качестве параметра?
Прямо пишем так
InputStream in=new BufferedFileInputStream("F:\\Java huashan.pdf");
Разве это не хорошо?
Давайте вернемся к предыдущему подклассу ins.У него есть более одного подкласса fileins, и у него есть несколько других подклассов. Если мы получаем подкласс буферов только после файлов, другие подклассы также должны быть производными от соответствующего подкласса буферов, чтобы использовать эту функцию. Это кажется очень избыточным. Конечный результатвзрыв подкласса
Итак, в мире Java есть основной принцип проектирования:Комбинация больше, чем интеграция
Таким образом, в мире Java IO многие классы не происходят непосредственно из Ipnstrem, но удерживают экземпляр ins
Как обертка вокруг них.
Внимательные люди обнаружат, что Bufferins и DataIns не являются прямыми расширениями ins, а расширяют
Что это за дизайн?
Хорошо известно, что наш ins является абстрактным классом.
public abstract class InputStream implements Closeable {
Таким образом, для того, чтобы мы могли улучшить класс io, например входные данные буферов, реализованы только некоторые из их расширенных методов, а те методы, которые не изменились, естественным образом помещаются в фильтры и реализуются по умолчанию.
Некоторые люди спросят: поскольку inputstream является абстрактным классом, почему реализация по умолчанию не написана в inputStream? Почему вы хотите добавить фильтры, чтобы написать это? давайте посмотрим на картинку
Мы можем подумать об этом, если напишем реализацию по умолчанию в InputStream и удалим слой filterIns,
new Bufferins(new FileInput("path"))
В настоящее время мы должны переписать методы ins по умолчанию для наших Buffins следующим образом:
InputStrean ins;
public void f(){
ins.f()
}
Потому что, если мы не напишем это так, то метод f наших буферов по умолчанию будет реализацией по умолчанию в ins, а не реализацией FileInput, которую мы передали.
Размышляя об этом, мы можем догадаться, что делает FilterInput.
так ты видишь
Разве класс FilterInput не помогает нам решить вышеуказанные болевые точки? Это может помочь нам избежать ручного копирования и вставки вызовов методов по умолчанию.
После анализа давайте суммируемся тем, какие проблемы обертка декоратора используется в мире Java IO, в основном используется для решения.
основное решениеНаследственные отношения слишком сложныпроблема, черезкомпозиция вместо наследования. Его основная функция – даватьОригинальный класс добавляет улучшения. Это важная основа для принятия решения о том, следует ли использовать режим декоратора.Он написан иначе, чем прокси.Прокси в основном добавляет функции, не связанные с исходной функцией, в то время как декоратор расширяет исходную функцию, или Он предназначен для добавления аналогичных функций, но с оптимизированными эффектами**. Кроме того, паттерн декоратор имеет еще одну особенность, т. е. он можетВложенность примитивного класса с несколькими декораторами. Чтобы соответствовать этому сценарию приложения, при проектированииКласс декоратора должен наследовать тот же абстрактный класс или интерфейс, что и исходный класс..