Эта статья является частью нашего курса Академии под названием « Шаблоны проектирования Java» .
В этом курсе вы изучите огромное количество шаблонов проектирования и увидите, как они реализуются и используются в Java. Вы поймете причины, почему шаблоны так важны, и узнаете, когда и как применять каждый из них. Проверьте это здесь !
Содержание
1. Легкая модель
Объектно-ориентированное программирование сделало программирование простым и интересным. Это облегчает работу программиста, моделируя сущности реального мира в мире программирования. Программист создает класс и создает его экземпляр, создавая его объект. Этот объект моделирует сущность реального мира и объекты внутри приложения координируют друг с другом, чтобы выполнить требуемую работу.
Но иногда слишком много объектов могут замедлить ход событий. Слишком много объектов может потреблять большой объем памяти и может замедлить работу приложения или даже вызвать проблемы с нехваткой памяти. Как хороший программист, нужно отслеживать экземпляры объектов и контролировать создание объектов в приложении. Это особенно верно, когда у нас много похожих объектов и два объекта из пула не имеют больших различий между ними.
Иногда объекты в приложении могут иметь большое сходство и иметь сходный вид (подобный вид здесь означает, что большинство их свойств имеют сходные значения, и только некоторые из них имеют разное значение). Если они также являются тяжелыми объектами для создания, они должны контролироваться разработчиком приложения. В противном случае они могут потреблять большую часть памяти и в конечном итоге замедлять работу всего приложения.
Шаблон Flyweight предназначен для управления созданием таких объектов и предоставляет базовый механизм кэширования. Это позволяет вам создавать один объект для каждого типа (тип здесь отличается от свойства этого объекта), и если вы запрашиваете объект с тем же свойством (уже созданным), он вернет вам тот же объект вместо создания нового один.
Прежде чем углубляться в детали шаблона Flyweight, давайте рассмотрим следующий сценарий: сайт, который позволяет пользователям создавать и выполнять программы в Интернете. Мы обсудим сценарий сейчас, а позже попробуем решить проблему с помощью шаблона Flyweight.
Сайт X-программирования позволяет пользователям создавать и выполнять программы, используя свой любимый язык программирования. Он предоставляет вам множество вариантов языка программирования. Вы выбираете один, пишите программу и запускаете ее, чтобы увидеть результат.
Но теперь сайт начал терять своих пользователей, причина в том, что сайт работает медленно. Пользователи больше не заинтересованы в этом. Сайт очень популярен, и иногда его могут использовать более тысячи программистов. Из-за этого сайт ползает. Но интенсивное использование не является реальной проблемой из-за медлительности сайта. Давайте посмотрим на основное программирование сайта, которое позволяет пользователям запускать и выполнять свою программу, и там будет раскрыта истинная проблема.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
|
package com.javacodegeeks.patterns.flyweightpattern;public class Code { private String code; public String getCode() { return code; } public void setCode(String code) { this.code = code; } } |
Приведенный выше класс используется для установки кода, выполняемого программистом, для его выполнения. Объект Code представляет собой легкий простой объект, имеющий code свойства вместе с его установщиком и получателем.
|
1
2
3
4
5
6
|
package com.javacodegeeks.patterns.flyweightpattern;public interface Platform { public void execute(Code code);} |
Интерфейс Platform реализован на конкретной языковой платформе для выполнения кода. У него есть один метод executes , который принимает объект Code качестве параметра.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
package com.javacodegeeks.patterns.flyweightpattern;public class JavaPlatform implements Platform { public JavaPlatform(){ System.out.println("JavaPlatform object created"); } @Override public void execute(Code code) { System.out.println("Compiling and executing Java code."); }} |
Вышеупомянутый класс реализует интерфейс Platform и обеспечивает реализацию для метода execute , чтобы выполнить код в Java.
Чтобы выполнить код, создается объект Code который содержит код и объект Platform для выполнения кода. Код выглядит так:
|
1
2
|
Platform platform = new JavaPlatform();platform.execute(code); |
Теперь предположим, что около 2 000 пользователей в сети выполняют свой код, что приводит к объектам 2k Code объектам 2k Platform . Объект Code является легковесным объектом, и для каждого пользовательского кода также должен быть один объект Code. Но Platform — это тяжелый объект, который используется для настройки среды исполнения. Создание слишком большого количества объектов Platform занимает много времени и является сложной задачей. Нам нужно контролировать создание объекта Platform который можно выполнить с помощью шаблона Flyweight, но перед этим давайте рассмотрим детали шаблона Flyweight.
2. Что такое шаблон Flyweight
Цель шаблона Flyweight — использовать общие объекты для эффективной поддержки большого количества мелкозернистых объектов. Flyweight — это общий объект, который может использоваться одновременно в нескольких контекстах. Flyweight действует как независимый объект в каждом контексте — он неотличим от экземпляра объекта, который не является общим. Flyweights не может делать предположения о контексте, в котором они работают. Ключевой концепцией здесь является различие между внутренним и внешним состоянием. Собственное состояние хранится в навесном весе; он состоит из информации, которая не зависит от контекста flyweight, что делает его доступным для совместного использования. Внешнее состояние зависит от контекста мухи и зависит от него и поэтому не может быть разделено. Клиентские объекты несут ответственность за передачу внешнего состояния к весу, когда это необходимо.
Рассмотрим сценарий приложения, который включает создание большого количества объектов, уникальных только с точки зрения нескольких параметров. Другими словами, эти объекты содержат некоторые внутренние, инвариантные данные, которые являются общими для всех объектов. Эти внутренние данные должны быть созданы и поддерживаться как часть каждого создаваемого объекта. Общее создание и обслуживание большой группы таких объектов может быть очень дорогим с точки зрения использования памяти и производительности. Шаблон Flyweight можно использовать в таких сценариях для разработки более эффективного способа создания объектов.
Вот диаграмма классов для шаблона проектирования Flyweight:
легкий вес
- Объявляет интерфейс, через который мухи могут получать и воздействовать на внешнее состояние.
ConcreteFlyweight
- Реализует интерфейс Flyweight и добавляет хранилище для внутреннего состояния, если оно есть. Объект ConcreteFlyweight должен быть разделяемым. Любое состояние, которое оно хранит, должно быть внутренним; то есть он должен быть независимым от контекста объекта ConcreteFlyweight.
FlyweightFactory
- Создает и управляет легковесными объектами.
- Гарантирует, что мухи распределяются правильно. Когда клиент запрашивает flyweight, объект FlyweightFactory предоставляет существующий экземпляр или создает его, если таковой не существует.
клиент
- Поддерживает ссылку на наименьший вес (ы).
- Вычисляет или сохраняет внешнее состояние весов в полете.
3. Решение проблемы
Чтобы решить вышеупомянутую проблему, мы предоставим класс фабрики платформ, который будет управлять созданием объектов Platform.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
package com.javacodegeeks.patterns.flyweightpattern;import java.util.HashMap;import java.util.Map;public final class PlatformFactory { private static Map<String, Platform> map = new HashMap<>(); private PlatformFactory(){ throw new AssertionError("Cannot instantiate the class"); } public static synchronized Platform getPlatformInstance(String platformType){ Platform platform = map.get(platformType); if(platform==null){ switch(platformType){ case "C" : platform = new CPlatform(); break; case "CPP" : platform = new CPPPlatform(); break; case "JAVA" : platform = new JavaPlatform(); break; case "RUBY" : platform = new RubyPlatform(); break; } map.put(platformType, platform); } return platform; }} |
Приведенный выше класс содержит статическую карту, которая содержит объект String качестве ключа и объект типа Platform качестве значения. Мы не хотим создавать экземпляр этого класса, поэтому просто держим его конструктор закрытым и бросаем AssertionError просто для того, чтобы избежать случайного создания объекта даже внутри класса.
Основным и единственным методом этого класса является метод getPlatformInstance . Это статический метод, в качестве параметра которого используется platformType . Этот platformType используется в качестве ключа на карте, он сначала проверяет карту, существует ли уже объект платформы, имеющий ключ, или нет. Если объект не найден, создается соответствующий объект платформы, он помещается в карту, а затем метод возвращает объект. В следующий раз, когда запрашивается тот же объект типа платформы, возвращается тот же существующий объект, а не новый объект.
Также обратите внимание, что метод getPlatformInstance synchronized , чтобы обеспечить безопасность потока при проверке и создании экземпляра объекта. В вышеприведенном примере отсутствует какое-либо внутреннее свойство разделяемого объекта, а только внешнее свойство, являющееся объектом кода, предоставленным клиентским кодом.
Теперь давайте проверим код.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.javacodegeeks.patterns.flyweightpattern;public class TestFlyweight { public static void main(String[] args) { Code code = new Code(); code.setCode("C Code..."); Platform platform = PlatformFactory.getPlatformInstance("C"); platform.execute(code); System.out.println("-------------------------------------"); code = new Code(); code.setCode("C Code2..."); platform = PlatformFactory.getPlatformInstance("C"); platform.execute(code); System.out.println("-------------------------------------"); code = new Code(); code.setCode("JAVA Code..."); platform = PlatformFactory.getPlatformInstance("JAVA"); platform.execute(code); System.out.println("-------------------------------------"); code = new Code(); code.setCode("JAVA Code2..."); platform = PlatformFactory.getPlatformInstance("JAVA"); platform.execute(code); System.out.println("-------------------------------------"); code = new Code(); code.setCode("RUBY Code..."); platform = PlatformFactory.getPlatformInstance("RUBY"); platform.execute(code); System.out.println("-------------------------------------"); code = new Code(); code.setCode("RUBY Code2..."); platform = PlatformFactory.getPlatformInstance("RUBY"); platform.execute(code); }} |
Приведенный выше код приведет к следующему выводу:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
CPlatform object createdCompiling and executing C code.-------------------------------------Compiling and executing C code.-------------------------------------JavaPlatform object createdCompiling and executing Java code.-------------------------------------Compiling and executing Java code.-------------------------------------RubyPlatform object createdCompiling and executing Ruby code.-------------------------------------Compiling and executing Ruby code. |
В приведенном выше классе мы сначала создали объект Code и установили в него код C. Затем мы попросили PlatformFactory предоставить платформу C для выполнения кода. Позже мы вызвали метод execute для возвращаемого объекта, минуя объект Code .
Мы выполнили ту же процедуру, то есть создали и установили объект Code , а затем запросили объект платформы, специфичный для кода. Вывод ясно показывает, что объекты платформы создаются только в первый раз, когда они запрашиваются; при следующих попытках возвращается тот же объект.
Другие классы, специфичные для платформы, похожи на класс JavaPlatform , уже показанный.
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
|
package com.javacodegeeks.patterns.flyweightpattern;public class CPlatform implements Platform { public CPlatform(){ System.out.println("CPlatform object created"); } @Override public void execute(Code code) { System.out.println("Compiling and executing C code."); }}package com.javacodegeeks.patterns.flyweightpattern;public class CPPPlatform implements Platform{ public CPPPlatform(){ System.out.println("CPPPlatform object created"); } @Override public void execute(Code code) { System.out.println("Compiling and executing CPP code."); }}package com.javacodegeeks.patterns.flyweightpattern;public class RubyPlatform implements Platform{ public RubyPlatform(){ System.out.println("RubyPlatform object created"); } @Override public void execute(Code code) { System.out.println("Compiling and executing Ruby code."); }} |
Если мы пересмотрим, что 2k пользователей одновременно используют сайт, то получится ровно 2k легкого объекта Code , и будут созданы только 4 тяжелых объекта платформы. Обратите внимание, что мы говорим о 4 объектах платформы, учитывая, что на каждый язык должен быть как минимум один пользователь. Например, если, скажем, ни один пользователь не кодировал с использованием Ruby, в этом сценарии создаются только 3 объекта платформы.
4. Когда использовать шаблон Flyweight
Эффективность модели Flyweight сильно зависит от того, как и где она используется. Примените шаблон «Вес», если выполняются все следующие условия:
- Приложение использует большое количество объектов.
- Стоимость хранения высока из-за огромного количества предметов.
- Большая часть состояния объекта может быть сделана внешней.
- Многие группы объектов могут быть заменены относительно небольшим количеством общих объектов после удаления внешнего состояния.
- Приложение не зависит от идентичности объекта. Поскольку объекты flyweight могут использоваться совместно, тесты идентичности будут возвращать true для концептуально различных объектов.
5. Легкий вес в JDK
Ниже приведены примеры использования шаблона Flyweight в JDK.
-
java.lang.Integer#valueOf(int)(также для логических, байтовых, символьных, коротких и длинных)
6. Загрузите исходный код
Это был урок по модели Flyweight. Вы можете скачать исходный код здесь: Flyweight Pattern Project
