├── .gitignore
├── LICENSE.txt
├── README.md
└── src
└── refactoring_guru
├── abstract_factory
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── app
│ └── Application.java
│ ├── buttons
│ ├── Button.java
│ ├── MacOSButton.java
│ └── WindowsButton.java
│ ├── checkboxes
│ ├── Checkbox.java
│ ├── MacOSCheckbox.java
│ └── WindowsCheckbox.java
│ └── factories
│ ├── GUIFactory.java
│ ├── MacOSFactory.java
│ └── WindowsFactory.java
├── adapter
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── adapters
│ └── SquarePegAdapter.java
│ ├── round
│ ├── RoundHole.java
│ └── RoundPeg.java
│ └── square
│ └── SquarePeg.java
├── bridge
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── devices
│ ├── Device.java
│ ├── Radio.java
│ └── Tv.java
│ └── remotes
│ ├── AdvancedRemote.java
│ ├── BasicRemote.java
│ └── Remote.java
├── builder
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── builders
│ ├── Builder.java
│ ├── CarBuilder.java
│ └── CarManualBuilder.java
│ ├── cars
│ ├── Car.java
│ ├── CarType.java
│ └── Manual.java
│ ├── components
│ ├── Engine.java
│ ├── GPSNavigator.java
│ ├── Transmission.java
│ └── TripComputer.java
│ └── director
│ └── Director.java
├── chain_of_responsibility
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── middleware
│ ├── Middleware.java
│ ├── RoleCheckMiddleware.java
│ ├── ThrottlingMiddleware.java
│ └── UserExistsMiddleware.java
│ └── server
│ └── Server.java
├── command
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── commands
│ ├── Command.java
│ ├── CommandHistory.java
│ ├── CopyCommand.java
│ ├── CutCommand.java
│ └── PasteCommand.java
│ └── editor
│ └── Editor.java
├── composite
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── editor
│ └── ImageEditor.java
│ └── shapes
│ ├── BaseShape.java
│ ├── Circle.java
│ ├── CompoundShape.java
│ ├── Dot.java
│ ├── Rectangle.java
│ └── Shape.java
├── decorator
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ └── decorators
│ ├── CompressionDecorator.java
│ ├── DataSource.java
│ ├── DataSourceDecorator.java
│ ├── EncryptionDecorator.java
│ └── FileDataSource.java
├── facade
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── facade
│ └── VideoConversionFacade.java
│ └── some_complex_media_library
│ ├── AudioMixer.java
│ ├── BitrateReader.java
│ ├── Codec.java
│ ├── CodecFactory.java
│ ├── MPEG4CompressionCodec.java
│ ├── OggCompressionCodec.java
│ └── VideoFile.java
├── factory_method
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── OutputDemo.txt
│ ├── buttons
│ ├── Button.java
│ ├── HtmlButton.java
│ └── WindowsButton.java
│ └── factory
│ ├── Dialog.java
│ ├── HtmlDialog.java
│ └── WindowsDialog.java
├── flyweight
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── OutputDemo.txt
│ ├── forest
│ └── Forest.java
│ └── trees
│ ├── Tree.java
│ ├── TreeFactory.java
│ └── TreeType.java
├── interpreter
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ └── expressions
│ ├── AbstractExpressions.java
│ ├── AndExpression.java
│ ├── Context.java
│ ├── OrExpression.java
│ └── VariableExpression.java
├── iterator
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── iterators
│ ├── FacebookIterator.java
│ ├── LinkedInIterator.java
│ └── ProfileIterator.java
│ ├── profile
│ └── Profile.java
│ ├── social_networks
│ ├── Facebook.java
│ ├── LinkedIn.java
│ └── SocialNetwork.java
│ └── spammer
│ └── SocialSpammer.java
├── mediator
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── components
│ ├── AddButton.java
│ ├── Component.java
│ ├── DeleteButton.java
│ ├── Filter.java
│ ├── List.java
│ ├── SaveButton.java
│ ├── TextBox.java
│ └── Title.java
│ └── mediator
│ ├── Editor.java
│ ├── Mediator.java
│ └── Note.java
├── memento
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── commands
│ ├── ColorCommand.java
│ ├── Command.java
│ └── MoveCommand.java
│ ├── editor
│ ├── Canvas.java
│ └── Editor.java
│ ├── history
│ ├── History.java
│ └── Memento.java
│ └── shapes
│ ├── BaseShape.java
│ ├── Circle.java
│ ├── CompoundShape.java
│ ├── Dot.java
│ ├── Rectangle.java
│ └── Shape.java
├── observer
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── editor
│ └── Editor.java
│ ├── listeners
│ ├── EmailNotificationListener.java
│ ├── EventListener.java
│ └── LogOpenListener.java
│ └── publisher
│ └── EventManager.java
├── prototype
├── caching
│ ├── Demo.java
│ ├── OutputDemo.txt
│ └── cache
│ │ └── BundledShapeCache.java
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ └── shapes
│ ├── Circle.java
│ ├── Rectangle.java
│ └── Shape.java
├── proxy
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── downloader
│ └── YouTubeDownloader.java
│ ├── proxy
│ └── YouTubeCacheProxy.java
│ └── some_cool_media_library
│ ├── ThirdPartyYouTubeClass.java
│ ├── ThirdPartyYouTubeLib.java
│ └── Video.java
├── singleton
└── example
│ ├── non_thread_safe
│ ├── DemoMultiThread.java
│ ├── DemoSingleThread.java
│ ├── OutputDemoMultiThread.txt
│ ├── OutputDemoSingleThread.txt
│ └── Singleton.java
│ └── thread_safe
│ ├── DemoMultiThread.java
│ ├── OutputDemoMultiThread.txt
│ └── Singleton.java
├── state
└── example
│ ├── Demo.java
│ ├── OutputDemo.png
│ ├── states
│ ├── LockedState.java
│ ├── PlayingState.java
│ ├── ReadyState.java
│ └── State.java
│ └── ui
│ ├── Player.java
│ └── UI.java
├── strategy
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ ├── order
│ └── Order.java
│ └── strategies
│ ├── CreditCard.java
│ ├── PayByCreditCard.java
│ ├── PayByPayPal.java
│ └── PayStrategy.java
├── template_method
└── example
│ ├── Demo.java
│ ├── OutputDemo.txt
│ └── networks
│ ├── Facebook.java
│ ├── Network.java
│ └── Twitter.java
└── visitor
└── example
├── Demo.java
├── OutputDemo.txt
├── shapes
├── Circle.java
├── CompoundShape.java
├── Dot.java
├── Rectangle.java
└── Shape.java
└── visitor
├── Visitor.java
└── XMLExportVisitor.java
/.gitignore:
--------------------------------------------------------------------------------
1 | .idea
2 | *.iml
3 | out
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Design Patterns in Java
2 |
3 | This repository is part of the [Refactoring.Guru](https://refactoring.guru/design-patterns) project.
4 |
5 | It contains Java examples for all classic GoF design patterns.
6 |
7 |
8 | ## Requirements
9 |
10 | The examples were written in Java 8, but also tested in Java 9.
11 |
12 | For the best experience, we recommend working with examples in IntelliJ IDEA. The Community Edition of IDE is available for free (https://www.jetbrains.com/idea/download/).
13 |
14 | After downloading or cloning this repository to your computer, import its root directory into a New project:
15 |
16 | - Either through start dialog: Select "Import Project" option and skip through the rest of the steps.
17 |
18 | - Or via the main menu: File > New > Project from Existing Sources...
19 |
20 | After importing the project, you will be able to run examples by right-clicking "Demo" files inside every example and selecting the "Run" command from the context menu.
21 |
22 |
23 | ## Roadmap
24 |
25 | - [ ] Add detailed comments all classes.
26 | - [ ] Add structure-only examples.
27 |
28 |
29 | ## Contributor's Guide
30 |
31 | We appreciate any help, whether it's a simple fix of a typo or a whole new example. Just [make a fork](https://help.github.com/articles/fork-a-repo/), do your change and submit a [pull request](https://help.github.com/articles/creating-a-pull-request-from-a-fork/).
32 |
33 | Here's a style guide which might help you to keep your changes consistent with our code:
34 |
35 | 1. All code should meet the [Google Java Style Guide](https://google.github.io/styleguide/javaguide.html)
36 |
37 | 2. Try to hard wrap the code at 80th's character. It helps to list the code on the website without scrollbars.
38 |
39 | 3. Examples should match following package convention: refactoring_guru.{pattern}.{example_name}. Example:
40 |
41 | ```java
42 | package refactoring_guru.factory_method.ui_example.buttons;
43 |
44 | class Button {
45 | ...
46 | ```
47 |
48 | 4. Places classes into separate files.
49 |
50 | 5. Group classes into sub-packages. It helps people to understand dependencies of a class by glancing over its imports. Example:
51 |
52 | ```java
53 | package refactoring_guru.factory_method.example.buttons;
54 |
55 | class Button {
56 | ...
57 | ```
58 |
59 | ```java
60 | package refactoring_guru.factory_method.example.factories;
61 |
62 | import Button;
63 |
64 | class Factory {
65 | ...
66 | ```
67 |
68 | 6. Comments may or may not have language tags in them, such as this:
69 |
70 | ```java
71 | /**
72 | * EN: All products families have the same varieties (MacOS/Windows).
73 | *
74 | * This is a MacOS variant of a button.
75 | *
76 | * RU: Все семейства продуктов имеют одни и те же вариации (MacOS/Windows).
77 | *
78 | * Это вариант кнопки под MacOS.
79 | */
80 | ```
81 |
82 | Don't be scared and ignore the non-English part of such comments. If you want to change something in a comment like this, then do it. Even if you do it wrong, we'll tell you how to fix it during the Pull Request.
83 |
84 |
85 | ## License
86 |
87 | This work is licensed under a Creative Commons Attribution-NonCommercial-NoDerivatives 4.0 International License.
88 |
89 |
90 |
91 |
92 | ## Credits
93 |
94 | Authors: Bohdan Herashchenko ([@b1ger](https://github.com/b1ger)) and Alexander Shvets ([@neochief](https://github.com/neochief))
95 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example;
2 |
3 | import refactoring_guru.abstract_factory.example.app.Application;
4 | import refactoring_guru.abstract_factory.example.factories.GUIFactory;
5 | import refactoring_guru.abstract_factory.example.factories.MacOSFactory;
6 | import refactoring_guru.abstract_factory.example.factories.WindowsFactory;
7 |
8 | /**
9 | * EN: Demo class. Everything comes together here.
10 | *
11 | * RU: Демо-класс. Здесь всё сводится воедино.
12 | */
13 | public class Demo {
14 |
15 | /**
16 | * EN: Application picks the factory type and creates it in run time
17 | * (usually at initialization stage), depending on the configuration or
18 | * environment variables.
19 | *
20 | * RU: Приложение выбирает тип и создаёт конкретные фабрики динамически
21 | * исходя из конфигурации или окружения.
22 | */
23 | private static Application configureApplication() {
24 | Application app;
25 | GUIFactory factory;
26 | String osName = System.getProperty("os.name").toLowerCase();
27 | if (osName.contains("mac")) {
28 | factory = new MacOSFactory();
29 | } else {
30 | factory = new WindowsFactory();
31 | }
32 | app = new Application(factory);
33 | return app;
34 | }
35 |
36 | public static void main(String[] args) {
37 | Application app = configureApplication();
38 | app.paint();
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | You create WindowsButton.
2 | You created WindowsCheckbox.
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/app/Application.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.app;
2 |
3 | import refactoring_guru.abstract_factory.example.buttons.Button;
4 | import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
5 | import refactoring_guru.abstract_factory.example.factories.GUIFactory;
6 |
7 | /**
8 | * EN: Factory users don't care which concrete factory they use since they work
9 | * with factories and products through abstract interfaces.
10 | *
11 | * RU: Код, использующий фабрику, не волнует с какой конкретно фабрикой он
12 | * работает. Все получатели продуктов работают с продуктами через абстрактный
13 | * интерфейс.
14 | */
15 | public class Application {
16 | private Button button;
17 | private Checkbox checkbox;
18 |
19 | public Application(GUIFactory factory) {
20 | button = factory.createButton();
21 | checkbox = factory.createCheckbox();
22 | }
23 |
24 | public void paint() {
25 | button.paint();
26 | checkbox.paint();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/buttons/Button.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.buttons;
2 |
3 | /**
4 | * EN: Abstract Factory assumes that you have several families of products,
5 | * structured into separate class hierarchies (Button/Checkbox). All products of
6 | * the same family have the common interface.
7 | *
8 | * This is the common interface for buttons family.
9 | *
10 | * RU: Паттерн предполагает, что у вас есть несколько семейств продуктов,
11 | * находящихся в отдельных иерархиях классов (Button/Checkbox). Продукты одного
12 | * семейства должны иметь общий интерфейс.
13 | *
14 | * Это — общий интерфейс для семейства продуктов кнопок.
15 | */
16 | public interface Button {
17 | void paint();
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/buttons/MacOSButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.buttons;
2 |
3 | /**
4 | * EN: All products families have the same varieties (MacOS/Windows).
5 | *
6 | * This is a MacOS variant of a button.
7 | *
8 | * RU: Все семейства продуктов имеют одни и те же вариации (MacOS/Windows).
9 | *
10 | * Это вариант кнопки под MacOS.
11 | */
12 | public class MacOSButton implements Button {
13 |
14 | @Override
15 | public void paint() {
16 | System.out.println("You have created MacOSButton.");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/buttons/WindowsButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.buttons;
2 |
3 | /**
4 | * EN: All products families have the same varieties (MacOS/Windows).
5 | *
6 | * This is another variant of a button.
7 | *
8 | * RU: Все семейства продуктов имеют одни и те же вариации (MacOS/Windows).
9 | *
10 | * Это вариант кнопки под Windows.
11 | */
12 | public class WindowsButton implements Button {
13 |
14 | @Override
15 | public void paint() {
16 | System.out.println("You have created WindowsButton.");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/checkboxes/Checkbox.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.checkboxes;
2 |
3 | /**
4 | * EN: Checkboxes is the second product family. It has the same variants as
5 | * buttons.
6 | *
7 | * RU: Чекбоксы — это второе семейство продуктов. Оно имеет те же вариации, что
8 | * и кнопки.
9 | */
10 | public interface Checkbox {
11 | void paint();
12 | }
13 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/checkboxes/MacOSCheckbox.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.checkboxes;
2 |
3 | /**
4 | * EN: All products families have the same varieties (MacOS/Windows).
5 | *
6 | * This is a variant of a checkbox.
7 | *
8 | * RU: Все семейства продуктов имеют одинаковые вариации (MacOS/Windows).
9 | *
10 | * Вариация чекбокса под MacOS.
11 | */
12 | public class MacOSCheckbox implements Checkbox {
13 |
14 | @Override
15 | public void paint() {
16 | System.out.println("You have created MacOSCheckbox.");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/checkboxes/WindowsCheckbox.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.checkboxes;
2 |
3 | /**
4 | * EN: All products families have the same varieties (MacOS/Windows).
5 | *
6 | * This is another variant of a checkbox.
7 | *
8 | * RU: Все семейства продуктов имеют одинаковые вариации (MacOS/Windows).
9 | *
10 | * Вариация чекбокса под Windows.
11 | */
12 | public class WindowsCheckbox implements Checkbox {
13 |
14 | @Override
15 | public void paint() {
16 | System.out.println("You have created WindowsCheckbox.");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/factories/GUIFactory.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.factories;
2 |
3 | import refactoring_guru.abstract_factory.example.buttons.Button;
4 | import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
5 |
6 | /**
7 | * EN: Abstract factory knows about all (abstract) product types.
8 | *
9 | * RU: Абстрактная фабрика знает обо всех (абстрактных) типах продуктов.
10 | */
11 | public interface GUIFactory {
12 | Button createButton();
13 | Checkbox createCheckbox();
14 | }
15 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/factories/MacOSFactory.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.factories;
2 |
3 | import refactoring_guru.abstract_factory.example.buttons.Button;
4 | import refactoring_guru.abstract_factory.example.buttons.MacOSButton;
5 | import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
6 | import refactoring_guru.abstract_factory.example.checkboxes.MacOSCheckbox;
7 |
8 | /**
9 | * EN: Each concrete factory extends basic factory and responsible for creating
10 | * products of a single variety.
11 | *
12 | * RU: Каждая конкретная фабрика знает и создаёт только продукты своей вариации.
13 | */
14 | public class MacOSFactory implements GUIFactory {
15 |
16 | @Override
17 | public Button createButton() {
18 | return new MacOSButton();
19 | }
20 |
21 | @Override
22 | public Checkbox createCheckbox() {
23 | return new MacOSCheckbox();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/refactoring_guru/abstract_factory/example/factories/WindowsFactory.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.abstract_factory.example.factories;
2 |
3 | import refactoring_guru.abstract_factory.example.buttons.Button;
4 | import refactoring_guru.abstract_factory.example.buttons.WindowsButton;
5 | import refactoring_guru.abstract_factory.example.checkboxes.Checkbox;
6 | import refactoring_guru.abstract_factory.example.checkboxes.WindowsCheckbox;
7 |
8 | /**
9 | * EN: Each concrete factory extends basic factory and responsible for creating
10 | * products of a single variety.
11 | *
12 | * RU: Каждая конкретная фабрика знает и создаёт только продукты своей вариации.
13 | */
14 | public class WindowsFactory implements GUIFactory {
15 |
16 | @Override
17 | public Button createButton() {
18 | return new WindowsButton();
19 | }
20 |
21 | @Override
22 | public Checkbox createCheckbox() {
23 | return new WindowsCheckbox();
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/refactoring_guru/adapter/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.adapter.example;
2 |
3 | import refactoring_guru.adapter.example.adapters.SquarePegAdapter;
4 | import refactoring_guru.adapter.example.round.RoundHole;
5 | import refactoring_guru.adapter.example.round.RoundPeg;
6 | import refactoring_guru.adapter.example.square.SquarePeg;
7 |
8 | /**
9 | * EN: Somewhere in client code...
10 | *
11 | * RU: Где-то в клиентском коде...
12 | */
13 | public class Demo {
14 | public static void main(String[] args) {
15 | // EN: Round fits round, no surprise.
16 | //
17 | // RU: Круглое к круглому — всё работает.
18 | RoundHole hole = new RoundHole(5);
19 | RoundPeg rpeg = new RoundPeg(5);
20 | if (hole.fits(rpeg)) {
21 | System.out.println("Round peg r5 fits round hole r5.");
22 | }
23 |
24 | SquarePeg smallSqPeg = new SquarePeg(2);
25 | SquarePeg largeSqPeg = new SquarePeg(20);
26 | // EN: hole.fits(smallSqPeg); // Won't compile.
27 | //
28 | // RU: hole.fits(smallSqPeg); // Не скомпилируется.
29 |
30 | // EN: Adapter solves the problem.
31 | //
32 | // RU: Адаптер решит проблему.
33 | SquarePegAdapter smallSqPegAdapter = new SquarePegAdapter(smallSqPeg);
34 | SquarePegAdapter largeSqPegAdapter = new SquarePegAdapter(largeSqPeg);
35 | if (hole.fits(smallSqPegAdapter)) {
36 | System.out.println("Square peg w2 fits round hole r5.");
37 | }
38 | if (!hole.fits(largeSqPegAdapter)) {
39 | System.out.println("Square peg w20 does not fit into round hole r5.");
40 | }
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/refactoring_guru/adapter/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Round peg r5 fits round hole r5.
2 | Square peg w2 fits round hole r5.
3 | Square peg w20 does not fit into round hole r5.
--------------------------------------------------------------------------------
/src/refactoring_guru/adapter/example/adapters/SquarePegAdapter.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.adapter.example.adapters;
2 |
3 | import refactoring_guru.adapter.example.round.RoundPeg;
4 | import refactoring_guru.adapter.example.square.SquarePeg;
5 |
6 | /**
7 | * EN: Adapter allows fitting square pegs into round holes.
8 | *
9 | * RU: Адаптер позволяет использовать КвадратныеКолышки и КруглыеОтверстия
10 | * вместе.
11 | */
12 | public class SquarePegAdapter extends RoundPeg {
13 | private SquarePeg peg;
14 |
15 | public SquarePegAdapter(SquarePeg peg) {
16 | this.peg = peg;
17 | }
18 |
19 | @Override
20 | public double getRadius() {
21 | double result;
22 | // EN: Calculate a minimum circle radius, which can fit this peg.
23 | //
24 | // RU: Рассчитываем минимальный радиус, в который пролезет этот колышек.
25 | result = (Math.sqrt(Math.pow((peg.getWidth() / 2), 2) * 2));
26 | return result;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/adapter/example/round/RoundHole.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.adapter.example.round;
2 |
3 | /**
4 | * EN: RoundHoles are compatible with RoundPegs.
5 | *
6 | * RU: КруглоеОтверстие совместимо с КруглымиКолышками.
7 | */
8 | public class RoundHole {
9 | private double radius;
10 |
11 | public RoundHole(double radius) {
12 | this.radius = radius;
13 | }
14 |
15 | public double getRadius() {
16 | return radius;
17 | }
18 |
19 | public boolean fits(RoundPeg peg) {
20 | boolean result;
21 | result = (this.getRadius() >= peg.getRadius());
22 | return result;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/refactoring_guru/adapter/example/round/RoundPeg.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.adapter.example.round;
2 |
3 | /**
4 | * EN: RoundPegs are compatible with RoundHoles.
5 | *
6 | * RU: КруглыеКолышки совместимы с КруглымиОтверстиями.
7 | */
8 | public class RoundPeg {
9 | private double radius;
10 |
11 | public RoundPeg() {}
12 |
13 | public RoundPeg(double radius) {
14 | this.radius = radius;
15 | }
16 |
17 | public double getRadius() {
18 | return radius;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/refactoring_guru/adapter/example/square/SquarePeg.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.adapter.example.square;
2 |
3 | /**
4 | * EN: SquarePegs are not compatible with RoundHoles (they were implemented by
5 | * previous development team). But we have to integrate them into our program.
6 | *
7 | * RU: КвадратныеКолышки несовместимы с КруглымиОтверстиями (они остались в
8 | * проекте после бывших разработчиков). Но мы должны как-то интегрировать их в
9 | * нашу систему.
10 | */
11 | public class SquarePeg {
12 | private double width;
13 |
14 | public SquarePeg(double width) {
15 | this.width = width;
16 | }
17 |
18 | public double getWidth() {
19 | return width;
20 | }
21 |
22 | public double getSquare() {
23 | double result;
24 | result = Math.pow(this.width, 2);
25 | return result;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example;
2 |
3 | import refactoring_guru.bridge.example.devices.Device;
4 | import refactoring_guru.bridge.example.devices.Radio;
5 | import refactoring_guru.bridge.example.devices.Tv;
6 | import refactoring_guru.bridge.example.remotes.AdvancedRemote;
7 | import refactoring_guru.bridge.example.remotes.BasicRemote;
8 |
9 | public class Demo {
10 | public static void main(String[] args) {
11 | testDevice(new Tv());
12 | testDevice(new Radio());
13 | }
14 |
15 | public static void testDevice(Device device) {
16 | System.out.println("Tests with basic remote.");
17 | BasicRemote basicRemote = new BasicRemote(device);
18 | basicRemote.power();
19 | device.printStatus();
20 |
21 | System.out.println("Tests with advanced remote.");
22 | AdvancedRemote advancedRemote = new AdvancedRemote(device);
23 | advancedRemote.power();
24 | advancedRemote.mute();
25 | device.printStatus();
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Tests with basic remote.
2 | Remote: power toggle
3 | ------------------------------------
4 | | I'm TV set.
5 | | I'm enabled
6 | | Current volume is 30%
7 | | Current channel is 1
8 | ------------------------------------
9 |
10 | Tests with advanced remote.
11 | Remote: power toggle
12 | Remote: mute
13 | ------------------------------------
14 | | I'm TV set.
15 | | I'm disabled
16 | | Current volume is 0%
17 | | Current channel is 1
18 | ------------------------------------
19 |
20 | Tests with basic remote.
21 | Remote: power toggle
22 | ------------------------------------
23 | | I'm radio.
24 | | I'm enabled
25 | | Current volume is 30%
26 | | Current channel is 1
27 | ------------------------------------
28 |
29 | Tests with advanced remote.
30 | Remote: power toggle
31 | Remote: mute
32 | ------------------------------------
33 | | I'm radio.
34 | | I'm disabled
35 | | Current volume is 0%
36 | | Current channel is 1
37 | ------------------------------------
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/devices/Device.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example.devices;
2 |
3 | public interface Device {
4 | boolean isEnabled();
5 |
6 | void enable();
7 |
8 | void disable();
9 |
10 | int getVolume();
11 |
12 | void setVolume(int percent);
13 |
14 | int getChannel();
15 |
16 | void setChannel(int channel);
17 |
18 | void printStatus();
19 | }
20 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/devices/Radio.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example.devices;
2 |
3 | public class Radio implements Device {
4 | private boolean on = false;
5 | private int volume = 30;
6 | private int channel = 1;
7 |
8 | @Override
9 | public boolean isEnabled() {
10 | return on;
11 | }
12 |
13 | @Override
14 | public void enable() {
15 | on = true;
16 | }
17 |
18 | @Override
19 | public void disable() {
20 | on = false;
21 | }
22 |
23 | @Override
24 | public int getVolume() {
25 | return volume;
26 | }
27 |
28 | @Override
29 | public void setVolume(int volume) {
30 | if (volume > 100) {
31 | this.volume = 100;
32 | } else if (volume < 0) {
33 | this.volume = 0;
34 | } else {
35 | this.volume = volume;
36 | }
37 | }
38 |
39 | @Override
40 | public int getChannel() {
41 | return channel;
42 | }
43 |
44 | @Override
45 | public void setChannel(int channel) {
46 | this.channel = channel;
47 | }
48 |
49 | @Override
50 | public void printStatus() {
51 | System.out.println("------------------------------------");
52 | System.out.println("| I'm radio.");
53 | System.out.println("| I'm " + (on ? "enabled" : "disabled"));
54 | System.out.println("| Current volume is " + volume + "%");
55 | System.out.println("| Current channel is " + channel);
56 | System.out.println("------------------------------------\n");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/devices/Tv.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example.devices;
2 |
3 | public class Tv implements Device {
4 | private boolean on = false;
5 | private int volume = 30;
6 | private int channel = 1;
7 |
8 | @Override
9 | public boolean isEnabled() {
10 | return on;
11 | }
12 |
13 | @Override
14 | public void enable() {
15 | on = true;
16 | }
17 |
18 | @Override
19 | public void disable() {
20 | on = false;
21 | }
22 |
23 | @Override
24 | public int getVolume() {
25 | return volume;
26 | }
27 |
28 | @Override
29 | public void setVolume(int volume) {
30 | if (volume > 100) {
31 | this.volume = 100;
32 | } else if (volume < 0) {
33 | this.volume = 0;
34 | } else {
35 | this.volume = volume;
36 | }
37 | }
38 |
39 | @Override
40 | public int getChannel() {
41 | return channel;
42 | }
43 |
44 | @Override
45 | public void setChannel(int channel) {
46 | this.channel = channel;
47 | }
48 |
49 | @Override
50 | public void printStatus() {
51 | System.out.println("------------------------------------");
52 | System.out.println("| I'm TV set.");
53 | System.out.println("| I'm " + (on ? "enabled" : "disabled"));
54 | System.out.println("| Current volume is " + volume + "%");
55 | System.out.println("| Current channel is " + channel);
56 | System.out.println("------------------------------------\n");
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/remotes/AdvancedRemote.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example.remotes;
2 |
3 | import refactoring_guru.bridge.example.devices.Device;
4 |
5 | public class AdvancedRemote extends BasicRemote {
6 |
7 | public AdvancedRemote(Device device) {
8 | super.device = device;
9 | }
10 |
11 | public void mute() {
12 | System.out.println("Remote: mute");
13 | device.setVolume(0);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/remotes/BasicRemote.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example.remotes;
2 |
3 | import refactoring_guru.bridge.example.devices.Device;
4 |
5 | public class BasicRemote implements Remote {
6 | protected Device device;
7 |
8 | public BasicRemote() {}
9 |
10 | public BasicRemote(Device device) {
11 | this.device = device;
12 | }
13 |
14 | @Override
15 | public void power() {
16 | System.out.println("Remote: power toggle");
17 | if (device.isEnabled()) {
18 | device.disable();
19 | } else {
20 | device.enable();
21 | }
22 | }
23 |
24 | @Override
25 | public void volumeDown() {
26 | System.out.println("Remote: volume down");
27 | device.setVolume(device.getVolume() - 10);
28 | }
29 |
30 | @Override
31 | public void volumeUp() {
32 | System.out.println("Remote: volume up");
33 | device.setVolume(device.getVolume() + 10);
34 | }
35 |
36 | @Override
37 | public void channelDown() {
38 | System.out.println("Remote: channel down");
39 | device.setChannel(device.getChannel() - 1);
40 | }
41 |
42 | @Override
43 | public void channelUp() {
44 | System.out.println("Remote: channel up");
45 | device.setChannel(device.getChannel() + 1);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/refactoring_guru/bridge/example/remotes/Remote.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.bridge.example.remotes;
2 |
3 | public interface Remote {
4 | void power();
5 |
6 | void volumeDown();
7 |
8 | void volumeUp();
9 |
10 | void channelDown();
11 |
12 | void channelUp();
13 | }
14 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example;
2 |
3 | import refactoring_guru.builder.example.builders.CarBuilder;
4 | import refactoring_guru.builder.example.builders.CarManualBuilder;
5 | import refactoring_guru.builder.example.cars.Car;
6 | import refactoring_guru.builder.example.cars.Manual;
7 | import refactoring_guru.builder.example.director.Director;
8 |
9 | /**
10 | * EN: Demo class. Everything comes together here.
11 | *
12 | * RU: Демо-класс. Здесь всё сводится воедино.
13 | */
14 | public class Demo {
15 |
16 | public static void main(String[] args) {
17 | Director director = new Director();
18 |
19 | // EN: Director gets the concrete builder object from the client
20 | // (application code). That's because application knows better which
21 | // builder to use to get a specific product.
22 | //
23 | // RU: Директор получает объект конкретного строителя от клиента
24 | // (приложения). Приложение само знает какой строитель использовать,
25 | // чтобы получить нужный продукт.
26 | CarBuilder builder = new CarBuilder();
27 | director.constructSportsCar(builder);
28 |
29 | // EN: The final product is often retrieved from a builder object, since
30 | // Director is not aware and not dependent on concrete builders and
31 | // products.
32 | //
33 | // RU: Готовый продукт возвращает строитель, так как Директор чаще всего
34 | // не знает и не зависит от конкретных классов строителей и продуктов.
35 | Car car = builder.getResult();
36 | System.out.println("Car built:\n" + car.getCarType());
37 |
38 |
39 | CarManualBuilder manualBuilder = new CarManualBuilder();
40 |
41 | // EN: Director may know several building recipes.
42 | //
43 | // RU: Директор может знать больше одного рецепта строительства.
44 | director.constructSportsCar(manualBuilder);
45 | Manual carManual = manualBuilder.getResult();
46 | System.out.println("\nCar manual built:\n" + carManual.print());
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Car built:
2 | SPORTS_CAR
3 |
4 | Car manual built:
5 | Type of car: SPORTS_CAR
6 | Count of seats: 2
7 | Engine: volume - 3.0; mileage - 0.0
8 | Transmission: SEMI_AUTOMATIC
9 | Trip Computer: Functional
10 | GPS Navigator: Functional
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/builders/Builder.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.builders;
2 |
3 | import refactoring_guru.builder.example.cars.CarType;
4 | import refactoring_guru.builder.example.components.Engine;
5 | import refactoring_guru.builder.example.components.GPSNavigator;
6 | import refactoring_guru.builder.example.components.Transmission;
7 | import refactoring_guru.builder.example.components.TripComputer;
8 |
9 | /**
10 | * EN: Builder interface defines all possible ways to configure a product.
11 | *
12 | * RU: Интерфейс Строителя объявляет все возможные этапы и шаги конфигурации
13 | * продукта.
14 | */
15 | public interface Builder {
16 | void setCarType(CarType type);
17 | void setSeats(int seats);
18 | void setEngine(Engine engine);
19 | void setTransmission(Transmission transmission);
20 | void setTripComputer(TripComputer tripComputer);
21 | void setGPSNavigator(GPSNavigator gpsNavigator);
22 | }
23 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/builders/CarBuilder.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.builders;
2 |
3 | import refactoring_guru.builder.example.cars.Car;
4 | import refactoring_guru.builder.example.cars.CarType;
5 | import refactoring_guru.builder.example.components.Engine;
6 | import refactoring_guru.builder.example.components.GPSNavigator;
7 | import refactoring_guru.builder.example.components.Transmission;
8 | import refactoring_guru.builder.example.components.TripComputer;
9 |
10 | /**
11 | * EN: Concrete builders implement steps defined in the common interface.
12 | *
13 | * RU: Конкретные строители реализуют шаги, объявленные в общем интерфейсе.
14 | */
15 | public class CarBuilder implements Builder {
16 | private CarType type;
17 | private int seats;
18 | private Engine engine;
19 | private Transmission transmission;
20 | private TripComputer tripComputer;
21 | private GPSNavigator gpsNavigator;
22 |
23 | public void setCarType(CarType type) {
24 | this.type = type;
25 | }
26 |
27 | @Override
28 | public void setSeats(int seats) {
29 | this.seats = seats;
30 | }
31 |
32 | @Override
33 | public void setEngine(Engine engine) {
34 | this.engine = engine;
35 | }
36 |
37 | @Override
38 | public void setTransmission(Transmission transmission) {
39 | this.transmission = transmission;
40 | }
41 |
42 | @Override
43 | public void setTripComputer(TripComputer tripComputer) {
44 | this.tripComputer = tripComputer;
45 | }
46 |
47 | @Override
48 | public void setGPSNavigator(GPSNavigator gpsNavigator) {
49 | this.gpsNavigator = gpsNavigator;
50 | }
51 |
52 | public Car getResult() {
53 | return new Car(type, seats, engine, transmission, tripComputer, gpsNavigator);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/builders/CarManualBuilder.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.builders;
2 |
3 | import refactoring_guru.builder.example.cars.Manual;
4 | import refactoring_guru.builder.example.cars.CarType;
5 | import refactoring_guru.builder.example.components.Engine;
6 | import refactoring_guru.builder.example.components.GPSNavigator;
7 | import refactoring_guru.builder.example.components.Transmission;
8 | import refactoring_guru.builder.example.components.TripComputer;
9 |
10 | /**
11 | * EN: Unlike other creational patterns, Builder can construct unrelated
12 | * products, which don't have the common interface.
13 | *
14 | * In this case we build a user manual for a car, using the same steps as we
15 | * built a car. This allows to produce manuals for specific car models,
16 | * configured with different features.
17 | *
18 | * RU: В отличие от других создающих паттернов, Строители могут создавать
19 | * совершенно разные продукты, не имеющие общего интерфейса.
20 | *
21 | * В данном случае мы производим руководство пользователя автомобиля с помощью
22 | * тех же шагов, что и сами автомобили. Это устройство позволит создавать
23 | * руководства под конкретные модели автомобилей, содержащие те или иные фичи.
24 | */
25 | public class CarManualBuilder implements Builder{
26 | private CarType type;
27 | private int seats;
28 | private Engine engine;
29 | private Transmission transmission;
30 | private TripComputer tripComputer;
31 | private GPSNavigator gpsNavigator;
32 |
33 | @Override
34 | public void setCarType(CarType type) {
35 | this.type = type;
36 | }
37 |
38 | @Override
39 | public void setSeats(int seats) {
40 | this.seats = seats;
41 | }
42 |
43 | @Override
44 | public void setEngine(Engine engine) {
45 | this.engine = engine;
46 | }
47 |
48 | @Override
49 | public void setTransmission(Transmission transmission) {
50 | this.transmission = transmission;
51 | }
52 |
53 | @Override
54 | public void setTripComputer(TripComputer tripComputer) {
55 | this.tripComputer = tripComputer;
56 | }
57 |
58 | @Override
59 | public void setGPSNavigator(GPSNavigator gpsNavigator) {
60 | this.gpsNavigator = gpsNavigator;
61 | }
62 |
63 | public Manual getResult() {
64 | return new Manual(type, seats, engine, transmission, tripComputer, gpsNavigator);
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/cars/Car.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.cars;
2 |
3 | import refactoring_guru.builder.example.components.Engine;
4 | import refactoring_guru.builder.example.components.GPSNavigator;
5 | import refactoring_guru.builder.example.components.Transmission;
6 | import refactoring_guru.builder.example.components.TripComputer;
7 |
8 | /**
9 | * EN: Car is a product class.
10 | *
11 | * RU: Автомобиль — это класс продукта.
12 | */
13 | public class Car {
14 | private final CarType carType;
15 | private final int seats;
16 | private final Engine engine;
17 | private final Transmission transmission;
18 | private final TripComputer tripComputer;
19 | private final GPSNavigator gpsNavigator;
20 | private double fuel = 0;
21 |
22 | public Car(CarType carType, int seats, Engine engine, Transmission transmission,
23 | TripComputer tripComputer, GPSNavigator gpsNavigator) {
24 | this.carType = carType;
25 | this.seats = seats;
26 | this.engine = engine;
27 | this.transmission = transmission;
28 | this.tripComputer = tripComputer;
29 | if (this.tripComputer != null) {
30 | this.tripComputer.setCar(this);
31 | }
32 | this.gpsNavigator = gpsNavigator;
33 | }
34 |
35 | public CarType getCarType() {
36 | return carType;
37 | }
38 |
39 | public double getFuel() {
40 | return fuel;
41 | }
42 |
43 | public void setFuel(double fuel) {
44 | this.fuel = fuel;
45 | }
46 |
47 | public int getSeats() {
48 | return seats;
49 | }
50 |
51 | public Engine getEngine() {
52 | return engine;
53 | }
54 |
55 | public Transmission getTransmission() {
56 | return transmission;
57 | }
58 |
59 | public TripComputer getTripComputer() {
60 | return tripComputer;
61 | }
62 |
63 | public GPSNavigator getGpsNavigator() {
64 | return gpsNavigator;
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/cars/CarType.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.cars;
2 |
3 | public enum CarType {
4 | CITY_CAR, SPORTS_CAR, SUV
5 | }
6 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/cars/Manual.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.cars;
2 |
3 | import refactoring_guru.builder.example.components.Engine;
4 | import refactoring_guru.builder.example.components.GPSNavigator;
5 | import refactoring_guru.builder.example.components.Transmission;
6 | import refactoring_guru.builder.example.components.TripComputer;
7 |
8 | /**
9 | * EN: Car manual is another product. Note that it does not have the same
10 | * ancestor as a Car. They are not related.
11 | *
12 | * RU: Руководство автомобиля — это второй продукт. Заметьте, что руководство и
13 | * сам автомобиль не имеют общего родительского класса. По сути, они независимы.
14 | */
15 | public class Manual {
16 | private final CarType carType;
17 | private final int seats;
18 | private final Engine engine;
19 | private final Transmission transmission;
20 | private final TripComputer tripComputer;
21 | private final GPSNavigator gpsNavigator;
22 |
23 | public Manual(CarType carType, int seats, Engine engine, Transmission transmission,
24 | TripComputer tripComputer, GPSNavigator gpsNavigator) {
25 | this.carType = carType;
26 | this.seats = seats;
27 | this.engine = engine;
28 | this.transmission = transmission;
29 | this.tripComputer = tripComputer;
30 | this.gpsNavigator = gpsNavigator;
31 | }
32 |
33 | public String print() {
34 | String info = "";
35 | info += "Type of car: " + carType + "\n";
36 | info += "Count of seats: " + seats + "\n";
37 | info += "Engine: volume - " + engine.getVolume() + "; mileage - " + engine.getMileage() + "\n";
38 | info += "Transmission: " + transmission + "\n";
39 | if (this.tripComputer != null) {
40 | info += "Trip Computer: Functional" + "\n";
41 | } else {
42 | info += "Trip Computer: N/A" + "\n";
43 | }
44 | if (this.gpsNavigator != null) {
45 | info += "GPS Navigator: Functional" + "\n";
46 | } else {
47 | info += "GPS Navigator: N/A" + "\n";
48 | }
49 | return info;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/components/Engine.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.components;
2 |
3 | /**
4 | * EN: Just another feature of a car.
5 | *
6 | * RU: Одна из фишек автомобиля.
7 | */
8 | public class Engine {
9 | private final double volume;
10 | private double mileage;
11 | private boolean started;
12 |
13 | public Engine(double volume, double mileage) {
14 | this.volume = volume;
15 | this.mileage = mileage;
16 | }
17 |
18 | public void on() {
19 | started = true;
20 | }
21 |
22 | public void off() {
23 | started = false;
24 | }
25 |
26 | public boolean isStarted() {
27 | return started;
28 | }
29 |
30 | public void go(double mileage) {
31 | if (started) {
32 | this.mileage += mileage;
33 | } else {
34 | System.err.println("Cannot go(), you must start engine first!");
35 | }
36 | }
37 |
38 | public double getVolume() {
39 | return volume;
40 | }
41 |
42 | public double getMileage() {
43 | return mileage;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/components/GPSNavigator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.components;
2 |
3 | /**
4 | * EN: Just another feature of a car.
5 | *
6 | * RU: Одна из фишек автомобиля.
7 | */
8 | public class GPSNavigator {
9 | private String route;
10 |
11 | public GPSNavigator() {
12 | this.route = "221b, Baker Street, London to Scotland Yard, 8-10 Broadway, London";
13 | }
14 |
15 | public GPSNavigator(String manualRoute) {
16 | this.route = manualRoute;
17 | }
18 |
19 | public String getRoute() {
20 | return route;
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/components/Transmission.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.components;
2 |
3 | /**
4 | * EN: Just another feature of a car.
5 | *
6 | * RU: Одна из фишек автомобиля.
7 | */
8 | public enum Transmission {
9 | SINGLE_SPEED, MANUAL, AUTOMATIC, SEMI_AUTOMATIC
10 | }
11 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/components/TripComputer.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.components;
2 |
3 | import refactoring_guru.builder.example.cars.Car;
4 |
5 | /**
6 | * EN: Just another feature of a car.
7 | *
8 | * RU: Одна из фишек автомобиля.
9 | */
10 | public class TripComputer {
11 |
12 | private Car car;
13 |
14 | public void setCar(Car car) {
15 | this.car = car;
16 | }
17 |
18 | public void showFuelLevel() {
19 | System.out.println("Fuel level: " + car.getFuel());
20 | }
21 |
22 | public void showStatus() {
23 | if (this.car.getEngine().isStarted()) {
24 | System.out.println("Car is started");
25 | } else {
26 | System.out.println("Car isn't started");
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/builder/example/director/Director.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.builder.example.director;
2 |
3 | import refactoring_guru.builder.example.builders.Builder;
4 | import refactoring_guru.builder.example.cars.CarType;
5 | import refactoring_guru.builder.example.components.Engine;
6 | import refactoring_guru.builder.example.components.GPSNavigator;
7 | import refactoring_guru.builder.example.components.Transmission;
8 | import refactoring_guru.builder.example.components.TripComputer;
9 |
10 | /**
11 | * EN: Director defines the order of building steps. It works with a builder
12 | * object through common Builder interface. Therefore it may not know what
13 | * product is being built.
14 | *
15 | * RU: Директор знает в какой последовательности заставлять работать строителя.
16 | * Он работает с ним через общий интерфейс Строителя. Из-за этого, он может не
17 | * знать какой конкретно продукт сейчас строится.
18 | */
19 | public class Director {
20 |
21 | public void constructSportsCar(Builder builder) {
22 | builder.setCarType(CarType.SPORTS_CAR);
23 | builder.setSeats(2);
24 | builder.setEngine(new Engine(3.0, 0));
25 | builder.setTransmission(Transmission.SEMI_AUTOMATIC);
26 | builder.setTripComputer(new TripComputer());
27 | builder.setGPSNavigator(new GPSNavigator());
28 | }
29 |
30 | public void constructCityCar(Builder builder) {
31 | builder.setCarType(CarType.CITY_CAR);
32 | builder.setSeats(2);
33 | builder.setEngine(new Engine(1.2, 0));
34 | builder.setTransmission(Transmission.AUTOMATIC);
35 | builder.setTripComputer(new TripComputer());
36 | builder.setGPSNavigator(new GPSNavigator());
37 | }
38 |
39 | public void constructSUV(Builder builder) {
40 | builder.setCarType(CarType.SUV);
41 | builder.setSeats(4);
42 | builder.setEngine(new Engine(2.5, 0));
43 | builder.setTransmission(Transmission.MANUAL);
44 | builder.setGPSNavigator(new GPSNavigator());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.chain_of_responsibility.example;
2 |
3 | import refactoring_guru.chain_of_responsibility.example.middleware.Middleware;
4 | import refactoring_guru.chain_of_responsibility.example.middleware.RoleCheckMiddleware;
5 | import refactoring_guru.chain_of_responsibility.example.middleware.ThrottlingMiddleware;
6 | import refactoring_guru.chain_of_responsibility.example.middleware.UserExistsMiddleware;
7 | import refactoring_guru.chain_of_responsibility.example.server.Server;
8 |
9 | import java.io.BufferedReader;
10 | import java.io.IOException;
11 | import java.io.InputStreamReader;
12 |
13 | /**
14 | * EN: Demo class. Everything comes together here.
15 | *
16 | * RU: Демо-класс. Здесь всё сводится воедино.
17 | */
18 | public class Demo {
19 | private static BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
20 | private static Server server;
21 |
22 | private static void init() {
23 | server = new Server();
24 | server.register("admin@example.com", "admin_pass");
25 | server.register("user@example.com", "user_pass");
26 |
27 | // EN: All checks are linked. Client can build various chains using the
28 | // same components.
29 | //
30 | // RU: Проверки связаны в одну цепь. Клиент может строить различные
31 | // цепи, используя одни и те же компоненты.
32 | Middleware middleware = Middleware.link(
33 | new ThrottlingMiddleware(2),
34 | new UserExistsMiddleware(server),
35 | new RoleCheckMiddleware()
36 | );
37 |
38 | // EN: Server gets a chain from client code.
39 | //
40 | // RU: Сервер получает цепочку от клиентского кода.
41 | server.setMiddleware(middleware);
42 | }
43 |
44 | public static void main(String[] args) throws IOException {
45 | init();
46 |
47 | boolean success;
48 | do {
49 | System.out.print("Enter email: ");
50 | String email = reader.readLine();
51 | System.out.print("Input password: ");
52 | String password = reader.readLine();
53 | success = server.logIn(email, password);
54 | } while (!success);
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Enter email: admin@example.com
2 | Input password: admin_pass
3 | Hello, admin!
4 | Authorization have been successful!
5 |
6 |
7 | Enter email: wrong@example.com
8 | Input password: wrong_pass
9 | This email is not registered!
10 | Enter email: wrong@example.com
11 | Input password: wrong_pass
12 | This email is not registered!
13 | Enter email: wrong@example.com
14 | Input password: wrong_pass
15 | Request limit exceeded!
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/middleware/Middleware.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.chain_of_responsibility.example.middleware;
2 |
3 | /**
4 | * EN: Base middleware class.
5 | *
6 | * RU: Базовый класс цепочки.
7 | */
8 | public abstract class Middleware {
9 | private Middleware next;
10 |
11 | /**
12 | * EN: Builds chains of middleware objects.
13 | *
14 | * RU: Помогает строить цепь из объектов-проверок.
15 | */
16 | public static Middleware link(Middleware first, Middleware... chain) {
17 | Middleware head = first;
18 | for (Middleware nextInChain: chain) {
19 | head.next = nextInChain;
20 | head = nextInChain;
21 | }
22 | return first;
23 | }
24 |
25 | /**
26 | * EN: Subclasses will implement this method with concrete checks.
27 | *
28 | * RU: Подклассы реализуют в этом методе конкретные проверки.
29 | */
30 | public abstract boolean check(String email, String password);
31 |
32 | /**
33 | * EN: Runs check on the next object in chain or ends traversing if we're in
34 | * last object in chain.
35 | *
36 | * RU: Запускает проверку в следующем объекте или завершает проверку, если
37 | * мы в последнем элементе цепи.
38 | */
39 | protected boolean checkNext(String email, String password) {
40 | if (next == null) {
41 | return true;
42 | }
43 | return next.check(email, password);
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/middleware/RoleCheckMiddleware.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.chain_of_responsibility.example.middleware;
2 |
3 | /**
4 | * EN: ConcreteHandler. Checks a user's role.
5 | *
6 | * RU: Конкретный элемент цепи обрабатывает запрос по-своему.
7 | */
8 | public class RoleCheckMiddleware extends Middleware {
9 | public boolean check(String email, String password) {
10 | if (email.equals("admin@example.com")) {
11 | System.out.println("Hello, admin!");
12 | return true;
13 | }
14 | System.out.println("Hello, user!");
15 | return checkNext(email, password);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/middleware/ThrottlingMiddleware.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.chain_of_responsibility.example.middleware;
2 |
3 | /**
4 | * EN: ConcreteHandler. Checks whether there are too many failed login requests.
5 | *
6 | * RU: Конкретный элемент цепи обрабатывает запрос по-своему.
7 | */
8 | public class ThrottlingMiddleware extends Middleware {
9 | private int requestPerMinute;
10 | private int request;
11 | private long currentTime;
12 |
13 | public ThrottlingMiddleware(int requestPerMinute) {
14 | this.requestPerMinute = requestPerMinute;
15 | this.currentTime = System.currentTimeMillis();
16 | }
17 |
18 | /**
19 | * EN: Please, not that checkNext() call can be inserted both in the
20 | * beginning of this method and in the end.
21 | *
22 | * This gives much more flexibility than a simple loop over all middleware
23 | * objects. For instance, an element of a chain can change the order of
24 | * checks by running its check after all other checks.
25 | *
26 | * RU: Обратите внимание, вызов checkNext() можно вставить как в начале
27 | * этого метода, так и в середине или в конце.
28 | *
29 | * Это даёт еще один уровень гибкости по сравнению с проверками в цикле.
30 | * Например, элемент цепи может пропустить все остальные проверки вперёд и
31 | * запустить свою проверку в конце.
32 | */
33 | public boolean check(String email, String password) {
34 | if (System.currentTimeMillis() > currentTime + 60_000) {
35 | request = 0;
36 | currentTime = System.currentTimeMillis();
37 | }
38 |
39 | request++;
40 |
41 | if (request > requestPerMinute) {
42 | System.out.println("Request limit exceeded!");
43 | Thread.currentThread().stop();
44 | }
45 | return checkNext(email, password);
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/middleware/UserExistsMiddleware.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.chain_of_responsibility.example.middleware;
2 |
3 | import refactoring_guru.chain_of_responsibility.example.server.Server;
4 |
5 | /**
6 | * EN: ConcreteHandler. Checks whether a user with the given credentials exists.
7 | *
8 | * RU: Конкретный элемент цепи обрабатывает запрос по-своему.
9 | */
10 | public class UserExistsMiddleware extends Middleware {
11 | private Server server;
12 |
13 | public UserExistsMiddleware(Server server) {
14 | this.server = server;
15 | }
16 |
17 | public boolean check(String email, String password) {
18 | if (!server.hasEmail(email)) {
19 | System.out.println("This email is not registered!");
20 | return false;
21 | }
22 | if (!server.isValidPassword(email, password)) {
23 | System.out.println("Wrong password!");
24 | return false;
25 | }
26 | return checkNext(email, password);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/chain_of_responsibility/example/server/Server.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.chain_of_responsibility.example.server;
2 |
3 | import refactoring_guru.chain_of_responsibility.example.middleware.Middleware;
4 |
5 | import java.util.HashMap;
6 | import java.util.Map;
7 |
8 | /**
9 | * EN: Server class.
10 | *
11 | * RU: Класс сервера.
12 | */
13 | public class Server {
14 | private Map users = new HashMap<>();
15 | private Middleware middleware;
16 |
17 | /**
18 | * EN: Client passes a chain of object to server. This improves flexibility
19 | * and makes testing the server class easier.
20 | *
21 | * RU: Клиент подаёт готовую цепочку в сервер. Это увеличивает гибкость и
22 | * упрощает тестирование класса сервера.
23 | */
24 | public void setMiddleware(Middleware middleware) {
25 | this.middleware = middleware;
26 | }
27 |
28 | /**
29 | * EN: Server gets email and password from client and sends the
30 | * authorization request to the chain.
31 | *
32 | * RU: Сервер получает email и пароль от клиента и запускает проверку
33 | * авторизации у цепочки.
34 | */
35 | public boolean logIn(String email, String password) {
36 | if (middleware.check(email, password)) {
37 | System.out.println("Authorization have been successful!");
38 |
39 | // EN: Do something useful here for authorized users.
40 | //
41 | // RU: Здесь должен быть какой-то полезный код, работающий для
42 | // авторизированных пользователей.
43 |
44 | return true;
45 | }
46 | return false;
47 | }
48 |
49 | public void register(String email, String password) {
50 | users.put(email, password);
51 | }
52 |
53 | public boolean hasEmail(String email) {
54 | return users.containsKey(email);
55 | }
56 |
57 | public boolean isValidPassword(String email, String password) {
58 | return users.get(email).equals(password);
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example;
2 |
3 | import refactoring_guru.command.example.editor.Editor;
4 |
5 | public class Demo {
6 | public static void main(String[] args) {
7 | Editor editor = new Editor();
8 | editor.init();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/command/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/commands/Command.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example.commands;
2 |
3 | import refactoring_guru.command.example.editor.Editor;
4 |
5 | public abstract class Command {
6 | public Editor editor;
7 | private String backup;
8 |
9 | Command(Editor editor) {
10 | this.editor = editor;
11 | }
12 |
13 | void backup() {
14 | backup = editor.textField.getText();
15 | }
16 |
17 | public void undo() {
18 | editor.textField.setText(backup);
19 | }
20 |
21 | public abstract boolean execute();
22 | }
23 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/commands/CommandHistory.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example.commands;
2 |
3 | import java.util.Stack;
4 |
5 | public class CommandHistory {
6 | private Stack history = new Stack<>();
7 |
8 | public void push(Command c) {
9 | history.push(c);
10 | }
11 |
12 | public Command pop() {
13 | return history.pop();
14 | }
15 |
16 | public boolean isEmpty() { return history.isEmpty(); }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/commands/CopyCommand.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example.commands;
2 |
3 | import refactoring_guru.command.example.editor.Editor;
4 |
5 | public class CopyCommand extends Command {
6 |
7 | public CopyCommand(Editor editor) {
8 | super(editor);
9 | }
10 |
11 | @Override
12 | public boolean execute() {
13 | editor.clipboard = editor.textField.getSelectedText();
14 | return false;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/commands/CutCommand.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example.commands;
2 |
3 | import refactoring_guru.command.example.editor.Editor;
4 |
5 | public class CutCommand extends Command {
6 |
7 | public CutCommand(Editor editor) {
8 | super(editor);
9 | }
10 |
11 | @Override
12 | public boolean execute() {
13 | if (editor.textField.getSelectedText().isEmpty()) return false;
14 |
15 | backup();
16 | String source = editor.textField.getText();
17 | editor.clipboard = editor.textField.getSelectedText();
18 | editor.textField.setText(cutString(source));
19 | return true;
20 | }
21 |
22 | private String cutString(String source) {
23 | String start = source.substring(0, editor.textField.getSelectionStart());
24 | String end = source.substring(editor.textField.getSelectionEnd());
25 | return start + end;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/commands/PasteCommand.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example.commands;
2 |
3 | import refactoring_guru.command.example.editor.Editor;
4 |
5 | public class PasteCommand extends Command {
6 |
7 | public PasteCommand(Editor editor) {
8 | super(editor);
9 | }
10 |
11 | @Override
12 | public boolean execute() {
13 | if (editor.clipboard == null || editor.clipboard.isEmpty()) return false;
14 |
15 | backup();
16 | editor.textField.insert(editor.clipboard, editor.textField.getCaretPosition());
17 | return true;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/refactoring_guru/command/example/editor/Editor.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.command.example.editor;
2 |
3 | import refactoring_guru.command.example.commands.*;
4 |
5 | import javax.swing.*;
6 | import java.awt.*;
7 | import java.awt.event.ActionEvent;
8 | import java.awt.event.ActionListener;
9 |
10 | public class Editor {
11 | public JTextArea textField;
12 | public String clipboard;
13 | private CommandHistory history = new CommandHistory();
14 |
15 | public void init() {
16 | JFrame frame = new JFrame("Text editor (type & use buttons, Luke!)");
17 | JPanel content = new JPanel();
18 | frame.setContentPane(content);
19 | frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
20 | content.setLayout(new BoxLayout(content, BoxLayout.Y_AXIS));
21 | textField = new JTextArea();
22 | textField.setLineWrap(true);
23 | content.add(textField);
24 | JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER));
25 | JButton ctrlC = new JButton("Ctrl+C");
26 | JButton ctrlX = new JButton("Ctrl+X");
27 | JButton ctrlV = new JButton("Ctrl+V");
28 | JButton ctrlZ = new JButton("Ctrl+Z");
29 | Editor editor = this;
30 | ctrlC.addActionListener(new ActionListener() {
31 | @Override
32 | public void actionPerformed(ActionEvent e) {
33 | executeCommand(new CopyCommand(editor));
34 | }
35 | });
36 | ctrlX.addActionListener(new ActionListener() {
37 | @Override
38 | public void actionPerformed(ActionEvent e) {
39 | executeCommand(new CutCommand(editor));
40 | }
41 | });
42 | ctrlV.addActionListener(new ActionListener() {
43 | @Override
44 | public void actionPerformed(ActionEvent e) {
45 | executeCommand(new PasteCommand(editor));
46 | }
47 | });
48 | ctrlZ.addActionListener(new ActionListener() {
49 | @Override
50 | public void actionPerformed(ActionEvent e) {
51 | undo();
52 | }
53 | });
54 | buttons.add(ctrlC);
55 | buttons.add(ctrlX);
56 | buttons.add(ctrlV);
57 | buttons.add(ctrlZ);
58 | content.add(buttons);
59 | frame.setSize(450, 200);
60 | frame.setLocationRelativeTo(null);
61 | frame.setVisible(true);
62 | }
63 |
64 | private void executeCommand(Command command) {
65 | if (command.execute()) {
66 | history.push(command);
67 | }
68 | }
69 |
70 | private void undo() {
71 | if (history.isEmpty()) return;
72 |
73 | Command command = history.pop();
74 | if (command != null) {
75 | command.undo();
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example;
2 |
3 | import refactoring_guru.composite.example.editor.ImageEditor;
4 | import refactoring_guru.composite.example.shapes.Circle;
5 | import refactoring_guru.composite.example.shapes.CompoundShape;
6 | import refactoring_guru.composite.example.shapes.Dot;
7 | import refactoring_guru.composite.example.shapes.Rectangle;
8 |
9 | import java.awt.*;
10 |
11 | public class Demo {
12 | public static void main(String[] args) {
13 | ImageEditor editor = new ImageEditor();
14 |
15 | editor.loadShapes(
16 | new Circle(10, 10, 10, Color.BLUE),
17 |
18 | new CompoundShape(
19 | new Circle(110, 110, 50, Color.RED),
20 | new Dot(160, 160, Color.RED)
21 | ),
22 |
23 | new CompoundShape(
24 | new Rectangle(250, 250, 100, 100, Color.GREEN),
25 | new Dot(240, 240, Color.GREEN),
26 | new Dot(240, 360, Color.GREEN),
27 | new Dot(360, 360, Color.GREEN),
28 | new Dot(360, 240, Color.GREEN)
29 | )
30 | );
31 | }
32 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/composite/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/editor/ImageEditor.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.editor;
2 |
3 | import refactoring_guru.composite.example.shapes.CompoundShape;
4 | import refactoring_guru.composite.example.shapes.Shape;
5 |
6 | import javax.swing.*;
7 | import javax.swing.border.Border;
8 | import java.awt.*;
9 | import java.awt.event.MouseAdapter;
10 | import java.awt.event.MouseEvent;
11 |
12 | public class ImageEditor {
13 | private EditorCanvas canvas;
14 | private CompoundShape allShapes = new CompoundShape();
15 |
16 | public ImageEditor() {
17 | canvas = new EditorCanvas();
18 | }
19 |
20 | public void loadShapes(Shape... shapes) {
21 | allShapes.clear();
22 | allShapes.add(shapes);
23 | canvas.refresh();
24 | }
25 |
26 | private class EditorCanvas extends Canvas {
27 | JFrame frame;
28 |
29 | private static final int PADDING = 10;
30 |
31 | EditorCanvas() {
32 | createFrame();
33 | refresh();
34 | addMouseListener(new MouseAdapter() {
35 | @Override
36 | public void mousePressed(MouseEvent e) {
37 | allShapes.unSelect();
38 | allShapes.selectChildAt(e.getX(), e.getY());
39 | e.getComponent().repaint();
40 | }
41 | });
42 | }
43 |
44 | void createFrame() {
45 | frame = new JFrame();
46 | frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
47 | frame.setLocationRelativeTo(null);
48 |
49 | JPanel contentPanel = new JPanel();
50 | Border padding = BorderFactory.createEmptyBorder(PADDING, PADDING, PADDING, PADDING);
51 | contentPanel.setBorder(padding);
52 | frame.setContentPane(contentPanel);
53 |
54 | frame.add(this);
55 | frame.setVisible(true);
56 | frame.getContentPane().setBackground(Color.LIGHT_GRAY);
57 | }
58 |
59 | public int getWidth() {
60 | return allShapes.getX() + allShapes.getWidth() + PADDING;
61 | }
62 |
63 | public int getHeight() {
64 | return allShapes.getY() + allShapes.getHeight() + PADDING;
65 | }
66 |
67 | void refresh() {
68 | this.setSize(getWidth(), getHeight());
69 | frame.pack();
70 | }
71 |
72 | public void paint(Graphics graphics) {
73 | allShapes.paint(graphics);
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/shapes/BaseShape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | abstract class BaseShape implements Shape {
6 | public int x;
7 | public int y;
8 | public Color color;
9 | private boolean selected = false;
10 |
11 | BaseShape(int x, int y, Color color) {
12 | this.x = x;
13 | this.y = y;
14 | this.color = color;
15 | }
16 |
17 | @Override
18 | public int getX() {
19 | return x;
20 | }
21 |
22 | @Override
23 | public int getY() {
24 | return y;
25 | }
26 |
27 | @Override
28 | public int getWidth() {
29 | return 0;
30 | }
31 |
32 | @Override
33 | public int getHeight() {
34 | return 0;
35 | }
36 |
37 | @Override
38 | public void move(int x, int y) {
39 | this.x += x;
40 | this.y += y;
41 | }
42 |
43 | @Override
44 | public boolean isInsideBounds(int x, int y) {
45 | return x > getX() && x < (getX() + getWidth()) &&
46 | y > getY() && y < (getY() + getHeight());
47 | }
48 |
49 | @Override
50 | public void select() {
51 | selected = true;
52 | }
53 |
54 | @Override
55 | public void unSelect() {
56 | selected = false;
57 | }
58 |
59 | @Override
60 | public boolean isSelected() {
61 | return selected;
62 | }
63 |
64 | void enableSelectionStyle(Graphics graphics) {
65 | graphics.setColor(Color.LIGHT_GRAY);
66 |
67 | Graphics2D g2 = (Graphics2D) graphics;
68 | float[] dash1 = {2.0f};
69 | g2.setStroke(new BasicStroke(1.0f,
70 | BasicStroke.CAP_BUTT,
71 | BasicStroke.JOIN_MITER,
72 | 2.0f, dash1, 0.0f));
73 | }
74 |
75 | void disableSelectionStyle(Graphics graphics) {
76 | graphics.setColor(color);
77 | Graphics2D g2 = (Graphics2D) graphics;
78 | g2.setStroke(new BasicStroke());
79 | }
80 |
81 |
82 | @Override
83 | public void paint(Graphics graphics) {
84 | if (isSelected()) {
85 | enableSelectionStyle(graphics);
86 | }
87 | else {
88 | disableSelectionStyle(graphics);
89 | }
90 |
91 | // ...
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/shapes/Circle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public class Circle extends BaseShape {
6 | public int radius;
7 |
8 | public Circle(int x, int y, int radius, Color color) {
9 | super(x, y, color);
10 | this.radius = radius;
11 | }
12 |
13 | @Override
14 | public int getWidth() {
15 | return radius * 2;
16 | }
17 |
18 | @Override
19 | public int getHeight() {
20 | return radius * 2;
21 | }
22 |
23 | @Override
24 | public void paint(Graphics graphics) {
25 | super.paint(graphics);
26 | graphics.drawOval(x, y, getWidth() - 1, getHeight() - 1);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/shapes/CompoundShape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.shapes;
2 |
3 | import java.awt.*;
4 | import java.util.ArrayList;
5 | import java.util.Arrays;
6 | import java.util.List;
7 |
8 | public class CompoundShape extends BaseShape {
9 | protected List children = new ArrayList<>();
10 |
11 | public CompoundShape(Shape... components) {
12 | super(0, 0, Color.BLACK);
13 | add(components);
14 | }
15 |
16 | public void add(Shape component) {
17 | children.add(component);
18 | }
19 |
20 | public void add(Shape... components) {
21 | children.addAll(Arrays.asList(components));
22 | }
23 |
24 | public void remove(Shape child) {
25 | children.remove(child);
26 | }
27 |
28 | public void remove(Shape... components) {
29 | children.removeAll(Arrays.asList(components));
30 | }
31 |
32 | public void clear() {
33 | children.clear();
34 | }
35 |
36 | @Override
37 | public int getX() {
38 | if (children.size() == 0) {
39 | return 0;
40 | }
41 | int x = children.get(0).getX();
42 | for (Shape child : children) {
43 | if (child.getX() < x) {
44 | x = child.getX();
45 | }
46 | }
47 | return x;
48 | }
49 |
50 | @Override
51 | public int getY() {
52 | if (children.size() == 0) {
53 | return 0;
54 | }
55 | int y = children.get(0).getY();
56 | for (Shape child : children) {
57 | if (child.getY() < y) {
58 | y = child.getY();
59 | }
60 | }
61 | return y;
62 | }
63 |
64 | @Override
65 | public int getWidth() {
66 | int maxWidth = 0;
67 | int x = getX();
68 | for (Shape child : children) {
69 | int childsRelativeX = child.getX() - x;
70 | int childWidth = childsRelativeX + child.getWidth();
71 | if (childWidth > maxWidth) {
72 | maxWidth = childWidth;
73 | }
74 | }
75 | return maxWidth;
76 | }
77 |
78 | @Override
79 | public int getHeight() {
80 | int maxHeight = 0;
81 | int y = getY();
82 | for (Shape child : children) {
83 | int childsRelativeY = child.getY() - y;
84 | int childHeight = childsRelativeY + child.getHeight();
85 | if (childHeight > maxHeight) {
86 | maxHeight = childHeight;
87 | }
88 | }
89 | return maxHeight;
90 | }
91 |
92 | @Override
93 | public void move(int x, int y) {
94 | for (Shape child : children) {
95 | child.move(x, y);
96 | }
97 | }
98 |
99 | @Override
100 | public boolean isInsideBounds(int x, int y) {
101 | for (Shape child : children) {
102 | if (child.isInsideBounds(x, y)) {
103 | return true;
104 | }
105 | }
106 | return false;
107 | }
108 |
109 | @Override
110 | public void unSelect() {
111 | super.unSelect();
112 | for (Shape child : children) {
113 | child.unSelect();
114 | }
115 | }
116 |
117 | public boolean selectChildAt(int x, int y) {
118 | for (Shape child : children) {
119 | if (child.isInsideBounds(x, y)) {
120 | child.select();
121 | return true;
122 | }
123 | }
124 | return false;
125 | }
126 |
127 | @Override
128 | public void paint(Graphics graphics) {
129 | if (isSelected()) {
130 | enableSelectionStyle(graphics);
131 | graphics.drawRect(getX() - 1, getY() - 1, getWidth() + 1, getHeight() + 1);
132 | disableSelectionStyle(graphics);
133 | }
134 |
135 | for (Shape child : children) {
136 | child.paint(graphics);
137 | }
138 | }
139 | }
140 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/shapes/Dot.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public class Dot extends BaseShape {
6 | private final int DOT_SIZE = 3;
7 |
8 | public Dot(int x, int y, Color color) {
9 | super(x, y, color);
10 | }
11 |
12 | @Override
13 | public int getWidth() {
14 | return DOT_SIZE;
15 | }
16 |
17 | @Override
18 | public int getHeight() {
19 | return DOT_SIZE;
20 | }
21 |
22 | @Override
23 | public void paint(Graphics graphics) {
24 | super.paint(graphics);
25 | graphics.fillRect(x - 1, y - 1, getWidth(), getHeight());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/shapes/Rectangle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public class Rectangle extends BaseShape {
6 | public int width;
7 | public int height;
8 |
9 | public Rectangle(int x, int y, int width, int height, Color color) {
10 | super(x, y, color);
11 | this.width = width;
12 | this.height = height;
13 | }
14 |
15 | @Override
16 | public int getWidth() {
17 | return width;
18 | }
19 |
20 | @Override
21 | public int getHeight() {
22 | return height;
23 | }
24 |
25 | @Override
26 | public void paint(Graphics graphics) {
27 | super.paint(graphics);
28 | graphics.drawRect(x, y, getWidth() - 1, getHeight() - 1);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/refactoring_guru/composite/example/shapes/Shape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.composite.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public interface Shape {
6 | int getX();
7 | int getY();
8 | int getWidth();
9 | int getHeight();
10 | void move(int x, int y);
11 | boolean isInsideBounds(int x, int y);
12 | void select();
13 | void unSelect();
14 | boolean isSelected();
15 | void paint(Graphics graphics);
16 | }
17 |
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.decorator.example;
2 |
3 | import refactoring_guru.decorator.example.decorators.*;
4 |
5 | public class Demo {
6 | public static void main(String[] args) {
7 | String salaryRecords = "Name,Salary\nJohn Smith,100000\nSteven Jobs,912000";
8 | DataSourceDecorator encoded = new CompressionDecorator(
9 | new EncryptionDecorator(
10 | new FileDataSource("out/OutputDemo.txt")));
11 | encoded.writeData(salaryRecords);
12 | DataSource plain = new FileDataSource("out/OutputDemo.txt");
13 |
14 | System.out.println("- Input ----------------");
15 | System.out.println(salaryRecords);
16 | System.out.println("- Encoded --------------");
17 | System.out.println(plain.readData());
18 | System.out.println("- Decoded --------------");
19 | System.out.println(encoded.readData());
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | - Input ----------------
2 | Name,Salary
3 | John Smith,100000
4 | Steven Jobs,912000
5 | - Encoded --------------
6 | Zkt7e1Q5eU8yUm1Qe0ZsdHJ2VXp6dDBKVnhrUHtUe0sxRUYxQkJIdjVLTVZ0dVI5Q2IwOXFISmVUMU5rcENCQmdxRlByaD4+
7 | - Decoded --------------
8 | Name,Salary
9 | John Smith,100000
10 | Steven Jobs,912000
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/decorators/CompressionDecorator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.decorator.example.decorators;
2 |
3 | import java.io.ByteArrayInputStream;
4 | import java.io.ByteArrayOutputStream;
5 | import java.io.IOException;
6 | import java.io.InputStream;
7 | import java.util.Base64;
8 | import java.util.zip.Deflater;
9 | import java.util.zip.DeflaterOutputStream;
10 | import java.util.zip.InflaterInputStream;
11 |
12 | public class CompressionDecorator extends DataSourceDecorator {
13 | private int compLevel = 6;
14 |
15 | public CompressionDecorator(DataSource source) {
16 | super(source);
17 | }
18 |
19 | public int getCompressionLevel() {
20 | return compLevel;
21 | }
22 |
23 | public void setCompressionLevel(int value) {
24 | compLevel = value;
25 | }
26 |
27 | @Override
28 | public void writeData(String data) {
29 | super.writeData(compress(data));
30 | }
31 |
32 | @Override
33 | public String readData() {
34 | return decompress(super.readData());
35 | }
36 |
37 | private String compress(String stringData) {
38 | byte[] data = stringData.getBytes();
39 | try {
40 | ByteArrayOutputStream bout = new ByteArrayOutputStream(512);
41 | DeflaterOutputStream dos = new DeflaterOutputStream(bout, new Deflater(compLevel));
42 | dos.write(data);
43 | dos.close();
44 | bout.close();
45 | return Base64.getEncoder().encodeToString(bout.toByteArray());
46 | } catch (IOException ex) {
47 | return null;
48 | }
49 | }
50 |
51 | private String decompress(String stringData) {
52 | byte[] data = Base64.getDecoder().decode(stringData);
53 | try {
54 | InputStream in = new ByteArrayInputStream(data);
55 | InflaterInputStream iin = new InflaterInputStream(in);
56 | ByteArrayOutputStream bout = new ByteArrayOutputStream(512);
57 | int b;
58 | while ((b = iin.read()) != -1) {
59 | bout.write(b);
60 | }
61 | in.close();
62 | iin.close();
63 | bout.close();
64 | return new String(bout.toByteArray());
65 | } catch (IOException ex) {
66 | return null;
67 | }
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/decorators/DataSource.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.decorator.example.decorators;
2 |
3 | public interface DataSource {
4 | void writeData(String data);
5 |
6 | String readData();
7 | }
8 |
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/decorators/DataSourceDecorator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.decorator.example.decorators;
2 |
3 | public abstract class DataSourceDecorator implements DataSource {
4 | private DataSource wrappee;
5 |
6 | DataSourceDecorator(DataSource source) {
7 | this.wrappee = source;
8 | }
9 |
10 | @Override
11 | public void writeData(String data) {
12 | wrappee.writeData(data);
13 | }
14 |
15 | @Override
16 | public String readData() {
17 | return wrappee.readData();
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/decorators/EncryptionDecorator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.decorator.example.decorators;
2 |
3 | import java.util.Base64;
4 |
5 | public class EncryptionDecorator extends DataSourceDecorator {
6 |
7 | public EncryptionDecorator(DataSource source) {
8 | super(source);
9 | }
10 |
11 | @Override
12 | public void writeData(String data) {
13 | super.writeData(encode(data));
14 | }
15 |
16 | @Override
17 | public String readData() {
18 | return decode(super.readData());
19 | }
20 |
21 | private String encode(String data) {
22 | byte[] result = data.getBytes();
23 | for (int i = 0; i < result.length; i++) {
24 | result[i] += (byte) 1;
25 | }
26 | return Base64.getEncoder().encodeToString(result);
27 | }
28 |
29 | private String decode(String data) {
30 | byte[] result = Base64.getDecoder().decode(data);
31 | for (int i = 0; i < result.length; i++) {
32 | result[i] -= (byte) 1;
33 | }
34 | return new String(result);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/refactoring_guru/decorator/example/decorators/FileDataSource.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.decorator.example.decorators;
2 |
3 | import java.io.*;
4 |
5 | public class FileDataSource implements DataSource {
6 | private String name;
7 |
8 | public FileDataSource(String name) {
9 | this.name = name;
10 | }
11 |
12 | @Override
13 | public void writeData(String data) {
14 | File file = new File(name);
15 | try (OutputStream fos = new FileOutputStream(file)) {
16 | fos.write(data.getBytes(), 0, data.length());
17 | } catch (IOException ex) {
18 | System.out.println(ex.getMessage());
19 | }
20 | }
21 |
22 | @Override
23 | public String readData() {
24 | char[] buffer = null;
25 | File file = new File(name);
26 | try (FileReader reader = new FileReader(file)) {
27 | buffer = new char[(int) file.length()];
28 | reader.read(buffer);
29 | } catch (IOException ex) {
30 | System.out.println(ex.getMessage());
31 | }
32 | return new String(buffer);
33 | }
34 | }
35 |
36 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example;
2 |
3 | import refactoring_guru.facade.example.facade.VideoConversionFacade;
4 |
5 | import java.io.File;
6 |
7 | public class Demo {
8 | public static void main(String[] args) {
9 | VideoConversionFacade converter = new VideoConversionFacade();
10 | File mp4Video = converter.convertVideo("youtubevideo.ogg", "mp4");
11 | // ...
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | VideoConversionFacade: conversion started.
2 | CodecFactory: extracting ogg audio...
3 | BitrateReader: reading file...
4 | BitrateReader: writing file...
5 | AudioMixer: fixing audio...
6 | VideoConversionFacade: conversion completed.
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/facade/VideoConversionFacade.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.facade;
2 |
3 | import refactoring_guru.facade.example.some_complex_media_library.*;
4 |
5 | import java.io.File;
6 |
7 | public class VideoConversionFacade {
8 | public File convertVideo(String fileName, String format) {
9 | System.out.println("VideoConversionFacade: conversion started.");
10 | VideoFile file = new VideoFile(fileName);
11 | Codec sourceCodec = CodecFactory.extract(file);
12 | Codec destinationCodec;
13 | if (format.equals("mp4")) {
14 | destinationCodec = new MPEG4CompressionCodec();
15 | } else {
16 | destinationCodec = new OggCompressionCodec();
17 | }
18 | VideoFile buffer = BitrateReader.read(file, sourceCodec);
19 | VideoFile intermediateResult = BitrateReader.convert(buffer, destinationCodec);
20 | File result = (new AudioMixer()).fix(intermediateResult);
21 | System.out.println("VideoConversionFacade: conversion completed.");
22 | return result;
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/AudioMixer.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | import java.io.File;
4 |
5 | public class AudioMixer {
6 | public File fix(VideoFile result){
7 | System.out.println("AudioMixer: fixing audio...");
8 | return new File("tmp");
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/BitrateReader.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | public class BitrateReader {
4 | public static VideoFile read(VideoFile file, Codec codec) {
5 | System.out.println("BitrateReader: reading file...");
6 | return file;
7 | }
8 |
9 | public static VideoFile convert(VideoFile buffer, Codec codec) {
10 | System.out.println("BitrateReader: writing file...");
11 | return buffer;
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/Codec.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | public interface Codec {
4 | }
5 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/CodecFactory.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | public class CodecFactory {
4 | public static Codec extract(VideoFile file) {
5 | String type = file.getCodecType();
6 | if (type.equals("mp4")) {
7 | System.out.println("CodecFactory: extracting mpeg audio...");
8 | return new MPEG4CompressionCodec();
9 | }
10 | else {
11 | System.out.println("CodecFactory: extracting ogg audio...");
12 | return new OggCompressionCodec();
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/MPEG4CompressionCodec.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | public class MPEG4CompressionCodec implements Codec {
4 | public String type = "mp4";
5 |
6 | }
7 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/OggCompressionCodec.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | public class OggCompressionCodec implements Codec {
4 | public String type = "ogg";
5 | }
6 |
--------------------------------------------------------------------------------
/src/refactoring_guru/facade/example/some_complex_media_library/VideoFile.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.facade.example.some_complex_media_library;
2 |
3 | public class VideoFile {
4 | private String name;
5 | private String codecType;
6 |
7 | public VideoFile(String name) {
8 | this.name = name;
9 | this.codecType = name.substring(name.indexOf(".") + 1);
10 | }
11 |
12 | public String getCodecType() {
13 | return codecType;
14 | }
15 |
16 | public String getName() {
17 | return name;
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example;
2 |
3 | import refactoring_guru.factory_method.example.factory.Dialog;
4 | import refactoring_guru.factory_method.example.factory.HtmlDialog;
5 | import refactoring_guru.factory_method.example.factory.WindowsDialog;
6 |
7 | /**
8 | * EN: Demo class. Everything comes together here.
9 | *
10 | * RU: Демо-класс. Здесь всё сводится воедино.
11 | */
12 | public class Demo {
13 | private static Dialog dialog;
14 |
15 | public static void main(String[] args) {
16 | configure();
17 | runBusinessLogic();
18 | }
19 |
20 | /**
21 | * EN: The concrete factory is usually chosen depending on configuration or
22 | * environment options.
23 | *
24 | * RU: Приложение создаёт определённую фабрику в зависимости от конфигурации
25 | * или окружения.
26 | */
27 | static void configure() {
28 | if (System.getProperty("os.name").equals("Windows 10")) {
29 | dialog = new WindowsDialog();
30 | } else {
31 | dialog = new HtmlDialog();
32 | }
33 | }
34 |
35 | /**
36 | * EN: All of the client code should work with factories and products
37 | * through abstract interfaces. This way it does not care which factory it
38 | * works with and what kind of product it returns.
39 | *
40 | * RU: Весь остальной клиентский код работает с фабрикой и продуктами только
41 | * через общий интерфейс, поэтому для него неважно какая фабрика была
42 | * создана.
43 | */
44 | static void runBusinessLogic() {
45 | dialog.renderWindow();
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/factory_method/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 |
2 | Click! Button says - 'Hello World!'
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/buttons/Button.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example.buttons;
2 |
3 | /**
4 | * EN: Common interface for all buttons.
5 | *
6 | * RU: Общий интерфейс для всех продуктов.
7 | */
8 | public interface Button {
9 | void render();
10 | void onClick();
11 | }
12 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/buttons/HtmlButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example.buttons;
2 |
3 | /**
4 | * EN: HTML button implementation.
5 | *
6 | * RU: Реализация HTML кнопок.
7 | */
8 | public class HtmlButton implements Button {
9 |
10 | public void render() {
11 | System.out.println("");
12 | onClick();
13 | }
14 |
15 | public void onClick() {
16 | System.out.println("Click! Button says - 'Hello World!'");
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/buttons/WindowsButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example.buttons;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 | import java.awt.event.ActionEvent;
6 | import java.awt.event.ActionListener;
7 |
8 | /**
9 | * EN: Windows button implementation.
10 | *
11 | * RU: Реализация нативных кнопок операционной системы.
12 | */
13 | public class WindowsButton implements Button {
14 | JPanel panel = new JPanel();
15 | JFrame frame = new JFrame();
16 | JButton button;
17 |
18 | public void render() {
19 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
20 | JLabel label = new JLabel("Hello World!");
21 | label.setOpaque(true);
22 | label.setBackground(new Color(235, 233, 126));
23 | label.setFont(new Font("Dialog", Font.BOLD, 44));
24 | label.setHorizontalAlignment(SwingConstants.CENTER);
25 | panel.setLayout(new FlowLayout(FlowLayout.CENTER));
26 | frame.getContentPane().add(panel);
27 | panel.add(label);
28 | onClick();
29 | panel.add(button);
30 |
31 | frame.setSize(320, 200);
32 | frame.setVisible(true);
33 | onClick();
34 | }
35 |
36 | public void onClick() {
37 | button = new JButton("Exit");
38 | button.addActionListener(new ActionListener() {
39 | public void actionPerformed(ActionEvent e) {
40 | frame.setVisible(false);
41 | System.exit(0);
42 | }
43 | });
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/factory/Dialog.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example.factory;
2 |
3 | import refactoring_guru.factory_method.example.buttons.Button;
4 |
5 | /**
6 | * EN: Base factory class. Note that "factory" is merely a role for the class.
7 | * It should have some core business logic which needs different products to be
8 | * created.
9 | *
10 | * RU: Базовый класс фабрики. Заметьте, что "фабрика" – это всего лишь
11 | * дополнительная роль для класса. Он уже имеет какую-то бизнес-логику, в
12 | * которой требуется создание разнообразных продуктов.
13 | */
14 | public abstract class Dialog {
15 |
16 | public void renderWindow() {
17 | // EN: ... other code ...
18 | //
19 | // RU: ... остальной код диалога ...
20 |
21 | Button okButton = createButton();
22 | okButton.render();
23 | }
24 |
25 | /**
26 | * EN: Subclasses will override this method in order to create specific
27 | * button objects.
28 | *
29 | * RU: Подклассы будут переопределять этот метод, чтобы создавать конкретные
30 | * объекты продуктов, разные для каждой фабрики.
31 | */
32 | public abstract Button createButton();
33 | }
34 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/factory/HtmlDialog.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example.factory;
2 |
3 | import refactoring_guru.factory_method.example.buttons.Button;
4 | import refactoring_guru.factory_method.example.buttons.HtmlButton;
5 |
6 | /**
7 | * EN: HTML Dialog will produce HTML buttons.
8 | *
9 | * RU: HTML-диалог.
10 | */
11 | public class HtmlDialog extends Dialog {
12 |
13 | @Override
14 | public Button createButton() {
15 | return new HtmlButton();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/factory_method/example/factory/WindowsDialog.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.factory_method.example.factory;
2 |
3 | import refactoring_guru.factory_method.example.buttons.Button;
4 | import refactoring_guru.factory_method.example.buttons.WindowsButton;
5 |
6 | /**
7 | * EN: Windows Dialog will produce Windows buttons.
8 | *
9 | * RU: Диалог на элементах операционной системы.
10 | */
11 | public class WindowsDialog extends Dialog {
12 |
13 | @Override
14 | public Button createButton() {
15 | return new WindowsButton();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.flyweight.example;
2 |
3 | import refactoring_guru.flyweight.example.forest.Forest;
4 |
5 | import java.awt.*;
6 |
7 | public class Demo {
8 | static int CANVAS_SIZE = 500;
9 | static int TREES_TO_DRAW = 1000000;
10 | static int TREE_TYPES = 2;
11 |
12 | public static void main(String[] args) {
13 | Forest forest = new Forest();
14 | for (int i = 0; i < Math.floor(TREES_TO_DRAW / TREE_TYPES); i++) {
15 | forest.plantTree(random(0, CANVAS_SIZE), random(0, CANVAS_SIZE),
16 | "Summer Oak", Color.GREEN, "Oak texture stub");
17 | forest.plantTree(random(0, CANVAS_SIZE), random(0, CANVAS_SIZE),
18 | "Autumn Oak", Color.ORANGE, "Autumn Oak texture stub");
19 | }
20 | forest.setSize(CANVAS_SIZE, CANVAS_SIZE);
21 | forest.setVisible(true);
22 |
23 | System.out.println(TREES_TO_DRAW + " trees drawn");
24 | System.out.println("---------------------");
25 | System.out.println("Memory usage:");
26 | System.out.println("Tree size (8 bytes) * " + TREES_TO_DRAW);
27 | System.out.println("+ TreeTypes size (~30 bytes) * " + TREE_TYPES + "");
28 | System.out.println("---------------------");
29 | System.out.println("Total: " + ((TREES_TO_DRAW * 8 + TREE_TYPES * 30) / 1024 / 1024) +
30 | "MB (instead of " + ((TREES_TO_DRAW * 38) / 1024 / 1024) + "MB)");
31 | }
32 |
33 | private static int random(int min, int max) {
34 | return min + (int) (Math.random() * ((max - min) + 1));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/flyweight/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | 1000000 trees drawn
2 | ---------------------
3 | Memory usage:
4 | Tree size (8 bytes) * 1000000
5 | + TreeTypes size (~30 bytes) * 2
6 | ---------------------
7 | Total: 7MB (instead of 36MB)
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/forest/Forest.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.flyweight.example.forest;
2 |
3 | import refactoring_guru.flyweight.example.trees.Tree;
4 | import refactoring_guru.flyweight.example.trees.TreeFactory;
5 | import refactoring_guru.flyweight.example.trees.TreeType;
6 |
7 | import javax.swing.*;
8 | import java.awt.*;
9 | import java.util.ArrayList;
10 | import java.util.List;
11 |
12 | public class Forest extends JFrame {
13 | private List trees = new ArrayList<>();
14 |
15 | public void plantTree(int x, int y, String name, Color color, String otherTreeData) {
16 | TreeType type = TreeFactory.getTreeType(name, color, otherTreeData);
17 | Tree tree = new Tree(x, y, type);
18 | trees.add(tree);
19 | }
20 |
21 | @Override
22 | public void paint(Graphics graphics) {
23 | for (Tree tree : trees) {
24 | tree.draw(graphics);
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/trees/Tree.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.flyweight.example.trees;
2 |
3 | import java.awt.*;
4 |
5 | public class Tree {
6 | private int x;
7 | private int y;
8 | private TreeType type;
9 |
10 | public Tree(int x, int y, TreeType type) {
11 | this.x = x;
12 | this.y = y;
13 | this.type = type;
14 | }
15 |
16 | public void draw(Graphics g) {
17 | type.draw(g, x, y);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/trees/TreeFactory.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.flyweight.example.trees;
2 |
3 | import java.awt.*;
4 | import java.util.HashMap;
5 | import java.util.Map;
6 |
7 | public class TreeFactory {
8 | static Map treeTypes = new HashMap<>();
9 |
10 | public static TreeType getTreeType(String name, Color color, String otherTreeData) {
11 | TreeType result = treeTypes.get(name);
12 | if (result == null) {
13 | result = new TreeType(name, color, otherTreeData);
14 | treeTypes.put(name, result);
15 | }
16 | return result;
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/flyweight/example/trees/TreeType.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.flyweight.example.trees;
2 |
3 | import java.awt.*;
4 |
5 | public class TreeType {
6 | private String name;
7 | private Color color;
8 | private String otherTreeData;
9 |
10 | public TreeType(String name, Color color, String otherTreeData) {
11 | this.name = name;
12 | this.color = color;
13 | this.otherTreeData = otherTreeData;
14 | }
15 |
16 | public void draw(Graphics g, int x, int y) {
17 | g.setColor(Color.BLACK);
18 | g.fillRect(x - 1, y, 3, 5);
19 | g.setColor(color);
20 | g.fillOval(x - 5, y - 10, 10, 10);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.interpreter.example;
2 |
3 | import refactoring_guru.interpreter.example.expressions.AndExpression;
4 | import refactoring_guru.interpreter.example.expressions.Context;
5 | import refactoring_guru.interpreter.example.expressions.OrExpression;
6 | import refactoring_guru.interpreter.example.expressions.VariableExpression;
7 |
8 | /**
9 | * EN: Interpreter Design Pattern
10 | *
11 | * Defines a representation for a grammar as well as a mechanism to understand and act upon the grammar.
12 | *
13 | * RU: Паттерн Интерпретатор
14 | *
15 | * Определяет грамматику простого языка, представляет предложения на этом языке и интерпретирует их.
16 | */
17 | public class Demo {
18 | private static void example1() throws Exception {
19 | var context = new Context();
20 |
21 | var a = new VariableExpression("A");
22 | var b = new VariableExpression("B");
23 | var c = new VariableExpression("C");
24 |
25 | // example 1:
26 | // A ∧ (B ∨ C)
27 | var example1 = new AndExpression(
28 | a,
29 | new OrExpression(b, c)
30 | );
31 |
32 | context.assign(a, true);
33 | context.assign(b, true);
34 | context.assign(c, false);
35 |
36 | var result = example1.interpret(context) ? "true" : "false";
37 |
38 | System.out.println("boolean expression A ∧ (B ∨ C) = " + result + ", with variables A=true, B=true, C=false");
39 | }
40 |
41 | private static void example2() throws Exception {
42 | var context = new Context();
43 |
44 | var a = new VariableExpression("A");
45 | var b = new VariableExpression("B");
46 | var c = new VariableExpression("C");
47 |
48 | // example 2:
49 | // B ∨ (A ∧ (B ∨ C))
50 | var example2 = new OrExpression(
51 | b,
52 | new AndExpression(
53 | a,
54 | new OrExpression(b, c)
55 | )
56 | );
57 |
58 | context.assign(a, false);
59 | context.assign(b, false);
60 | context.assign(c, true);
61 |
62 | var result2 = example2.interpret(context) ? "true" : "false";
63 |
64 | System.out.println("boolean expression B ∨ (A ∧ (B ∨ C)) = " + result2 + ", with variables A=false, B=false, C=true");
65 | }
66 |
67 | public static void main(String[] args) throws Exception {
68 | example1();
69 | example2();
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | boolean expression A ∧ (B ∨ C) = true, with variables A=true, B=true, C=false
2 | boolean expression B ∨ (A ∧ (B ∨ C)) = false, with variables A=false, B=false, C=true
3 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/expressions/AbstractExpressions.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.interpreter.example.expressions;
2 |
3 | public abstract class AbstractExpressions {
4 | public abstract boolean interpret(Context context) throws Exception;
5 | }
6 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/expressions/AndExpression.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.interpreter.example.expressions;
2 |
3 | public class AndExpression extends AbstractExpressions {
4 | private final AbstractExpressions first;
5 | private final AbstractExpressions second;
6 |
7 | public AndExpression(AbstractExpressions first, AbstractExpressions second) {
8 | this.first = first;
9 | this.second = second;
10 | }
11 |
12 | public boolean interpret(Context context) throws Exception {
13 | return this.first.interpret(context) && this.second.interpret(context);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/expressions/Context.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.interpreter.example.expressions;
2 |
3 | import java.util.HashMap;
4 |
5 | public class Context {
6 | HashMap poolVariables = new HashMap<>();
7 |
8 | public boolean lookUp(String name) throws Exception {
9 | if (!poolVariables.containsKey(name)) {
10 | throw new Exception("No exist variable: name");
11 | }
12 |
13 | return this.poolVariables.get(name);
14 | }
15 |
16 | public void assign(VariableExpression variable, boolean value) {
17 | this.poolVariables.put(variable.getName(), value);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/expressions/OrExpression.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.interpreter.example.expressions;
2 |
3 | public class OrExpression extends AbstractExpressions {
4 | private final AbstractExpressions first;
5 | private final AbstractExpressions second;
6 |
7 | public OrExpression(AbstractExpressions first, AbstractExpressions second) {
8 | this.first = first;
9 | this.second = second;
10 | }
11 |
12 | public boolean interpret(Context context) throws Exception {
13 | return this.first.interpret(context) || this.second.interpret(context);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/src/refactoring_guru/interpreter/example/expressions/VariableExpression.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.interpreter.example.expressions;
2 |
3 | public class VariableExpression extends AbstractExpressions {
4 | private final String name;
5 |
6 | public VariableExpression(String name) {
7 | this.name = name;
8 | }
9 |
10 | public boolean interpret(Context context) throws Exception {
11 | return context.lookUp(this.name);
12 | }
13 |
14 | public String getName() {
15 | return this.name;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example;
2 |
3 | import refactoring_guru.iterator.example.profile.Profile;
4 | import refactoring_guru.iterator.example.social_networks.Facebook;
5 | import refactoring_guru.iterator.example.social_networks.LinkedIn;
6 | import refactoring_guru.iterator.example.social_networks.SocialNetwork;
7 | import refactoring_guru.iterator.example.spammer.SocialSpammer;
8 |
9 | import java.util.ArrayList;
10 | import java.util.List;
11 | import java.util.Scanner;
12 |
13 | /**
14 | * EN: Demo class. Everything comes together here.
15 | *
16 | * RU: Демо-класс. Здесь всё сводится воедино.
17 | */
18 | public class Demo {
19 | public static Scanner scanner = new Scanner(System.in);
20 |
21 | public static void main(String[] args) {
22 | System.out.println("Please specify social network to target spam tool (default:Facebook):");
23 | System.out.println("1. Facebook");
24 | System.out.println("2. LinkedIn");
25 | String choice = scanner.nextLine();
26 |
27 | SocialNetwork network;
28 | if (choice.equals("2")) {
29 | network = new LinkedIn(createTestProfiles());
30 | }
31 | else {
32 | network = new Facebook(createTestProfiles());
33 | }
34 |
35 | SocialSpammer spammer = new SocialSpammer(network);
36 | spammer.sendSpamToFriends("anna.smith@bing.com",
37 | "Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?");
38 | spammer.sendSpamToCoworkers("anna.smith@bing.com",
39 | "Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].");
40 | }
41 |
42 | public static List createTestProfiles() {
43 | List data = new ArrayList();
44 | data.add(new Profile("anna.smith@bing.com", "Anna Smith", "friends:mad_max@ya.com", "friends:catwoman@yahoo.com", "coworkers:sam@amazon.com"));
45 | data.add(new Profile("mad_max@ya.com", "Maximilian", "friends:anna.smith@bing.com", "coworkers:sam@amazon.com"));
46 | data.add(new Profile("bill@microsoft.eu", "Billie", "coworkers:avanger@ukr.net"));
47 | data.add(new Profile("avanger@ukr.net", "John Day", "coworkers:bill@microsoft.eu"));
48 | data.add(new Profile("sam@amazon.com", "Sam Kitting", "coworkers:anna.smith@bing.com", "coworkers:mad_max@ya.com", "friends:catwoman@yahoo.com"));
49 | data.add(new Profile("catwoman@yahoo.com", "Liza", "friends:anna.smith@bing.com", "friends:sam@amazon.com"));
50 | return data;
51 | }
52 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Please specify social network to target spam tool (default:Facebook):
2 | 1. Facebook
3 | 2. LinkedIn
4 | > 1
5 |
6 | Iterating over friends...
7 |
8 | Facebook: Loading 'friends' list of 'anna.smith@bing.com' over the network...
9 | Facebook: Loading profile 'mad_max@ya.com' over the network...
10 | Sent message to: 'mad_max@ya.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?'
11 | Facebook: Loading profile 'catwoman@yahoo.com' over the network...
12 | Sent message to: 'catwoman@yahoo.com'. Message body: 'Hey! This is Anna's friend Josh. Can you do me a favor and like this post [link]?'
13 |
14 | Iterating over coworkers...
15 |
16 | Facebook: Loading 'coworkers' list of 'anna.smith@bing.com' over the network...
17 | Facebook: Loading profile 'sam@amazon.com' over the network...
18 | Sent message to: 'sam@amazon.com'. Message body: 'Hey! This is Anna's boss Jason. Anna told me you would be interested in [link].'
19 |
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/iterators/FacebookIterator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.iterators;
2 |
3 | import refactoring_guru.iterator.example.profile.Profile;
4 | import refactoring_guru.iterator.example.social_networks.Facebook;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class FacebookIterator implements ProfileIterator {
10 | private Facebook facebook;
11 | private String type;
12 | private String email;
13 | private int currentPosition = 0;
14 | private List emails = new ArrayList<>();
15 | private List profiles = new ArrayList<>();
16 |
17 | public FacebookIterator(Facebook facebook, String type, String email) {
18 | this.facebook = facebook;
19 | this.type = type;
20 | this.email = email;
21 | }
22 |
23 | private void lazyLoad() {
24 | if (emails.size() == 0) {
25 | List profiles = facebook.requestProfileFriendsFromFacebook(this.email, this.type);
26 | for (String profile : profiles) {
27 | this.emails.add(profile);
28 | this.profiles.add(null);
29 | }
30 | }
31 | }
32 |
33 | @Override
34 | public boolean hasNext() {
35 | lazyLoad();
36 | return currentPosition < emails.size();
37 | }
38 |
39 | @Override
40 | public Profile getNext() {
41 | if (!hasNext()) {
42 | return null;
43 | }
44 |
45 | String friendEmail = emails.get(currentPosition);
46 | Profile friendProfile = profiles.get(currentPosition);
47 | if (friendProfile == null) {
48 | friendProfile = facebook.requestProfileFromFacebook(friendEmail);
49 | profiles.set(currentPosition, friendProfile);
50 | }
51 | currentPosition++;
52 | return friendProfile;
53 | }
54 |
55 | @Override
56 | public void reset() {
57 | currentPosition = 0;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/iterators/LinkedInIterator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.iterators;
2 |
3 | import refactoring_guru.iterator.example.profile.Profile;
4 | import refactoring_guru.iterator.example.social_networks.LinkedIn;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class LinkedInIterator implements ProfileIterator {
10 | private LinkedIn linkedIn;
11 | private String type;
12 | private String email;
13 | private int currentPosition = 0;
14 | private List emails = new ArrayList<>();
15 | private List contacts = new ArrayList<>();
16 |
17 | public LinkedInIterator(LinkedIn linkedIn, String type, String email) {
18 | this.linkedIn = linkedIn;
19 | this.type = type;
20 | this.email = email;
21 | }
22 |
23 | private void lazyLoad() {
24 | if (emails.size() == 0) {
25 | List profiles = linkedIn.requestRelatedContactsFromLinkedInAPI(this.email, this.type);
26 | for (String profile : profiles) {
27 | this.emails.add(profile);
28 | this.contacts.add(null);
29 | }
30 | }
31 | }
32 |
33 | @Override
34 | public boolean hasNext() {
35 | lazyLoad();
36 | return currentPosition < emails.size();
37 | }
38 |
39 | @Override
40 | public Profile getNext() {
41 | if (!hasNext()) {
42 | return null;
43 | }
44 |
45 | String friendEmail = emails.get(currentPosition);
46 | Profile friendContact = contacts.get(currentPosition);
47 | if (friendContact == null) {
48 | friendContact = linkedIn.requestContactInfoFromLinkedInAPI(friendEmail);
49 | contacts.set(currentPosition, friendContact);
50 | }
51 | currentPosition++;
52 | return friendContact;
53 | }
54 |
55 | @Override
56 | public void reset() {
57 | currentPosition = 0;
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/iterators/ProfileIterator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.iterators;
2 |
3 | import refactoring_guru.iterator.example.profile.Profile;
4 |
5 | public interface ProfileIterator {
6 | boolean hasNext();
7 |
8 | Profile getNext();
9 |
10 | void reset();
11 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/profile/Profile.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.profile;
2 |
3 | import java.util.ArrayList;
4 | import java.util.HashMap;
5 | import java.util.List;
6 | import java.util.Map;
7 |
8 | public class Profile {
9 | private String name;
10 | private String email;
11 | private Map> contacts = new HashMap<>();
12 |
13 | public Profile(String email, String name, String... contacts) {
14 | this.email = email;
15 | this.name = name;
16 |
17 | // Parse contact list from a set of "friend:email@gmail.com" pairs.
18 | for (String contact : contacts) {
19 | String[] parts = contact.split(":");
20 | String contactType = "friend", contactEmail;
21 | if (parts.length == 1) {
22 | contactEmail = parts[0];
23 | }
24 | else {
25 | contactType = parts[0];
26 | contactEmail = parts[1];
27 | }
28 | if (!this.contacts.containsKey(contactType)) {
29 | this.contacts.put(contactType, new ArrayList<>());
30 | }
31 | this.contacts.get(contactType).add(contactEmail);
32 | }
33 | }
34 |
35 | public String getEmail() {
36 | return email;
37 | }
38 |
39 | public String getName() {
40 | return name;
41 | }
42 |
43 | public List getContacts(String contactType) {
44 | if (!this.contacts.containsKey(contactType)) {
45 | this.contacts.put(contactType, new ArrayList<>());
46 | }
47 | return contacts.get(contactType);
48 | }
49 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/social_networks/Facebook.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.social_networks;
2 |
3 | import refactoring_guru.iterator.example.iterators.FacebookIterator;
4 | import refactoring_guru.iterator.example.iterators.ProfileIterator;
5 | import refactoring_guru.iterator.example.profile.Profile;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class Facebook implements SocialNetwork {
11 | private List profiles;
12 |
13 | public Facebook(List cache) {
14 | if (cache != null) {
15 | this.profiles = cache;
16 | } else {
17 | this.profiles = new ArrayList<>();
18 | }
19 | }
20 |
21 | public Profile requestProfileFromFacebook(String profileEmail) {
22 | // EN: Here would be a POST request to one of the Facebook API
23 | // endpoints. Instead, we emulates long network connection, which you
24 | // would expect in the real life...
25 | //
26 | // RU: Здесь бы был POST запрос к одному из адресов API Facebook. Но
27 | // вместо этого мы эмулируем долгое сетевое соединение, прямо как в
28 | // реальной жизни...
29 | simulateNetworkLatency();
30 | System.out.println("Facebook: Loading profile '" + profileEmail + "' over the network...");
31 |
32 | // EN: ...and return test data.
33 | //
34 | // RU: ...и возвращаем тестовые данные.
35 | return findProfile(profileEmail);
36 | }
37 |
38 | public List requestProfileFriendsFromFacebook(String profileEmail, String contactType) {
39 | // EN: Here would be a POST request to one of the Facebook API
40 | // endpoints. Instead, we emulates long network connection, which you
41 | // would expect in the real life...
42 | //
43 | // RU: Здесь бы был POST запрос к одному из адресов API Facebook. Но
44 | // вместо этого мы эмулируем долгое сетевое соединение, прямо как в
45 | // реальной жизни...
46 | simulateNetworkLatency();
47 | System.out.println("Facebook: Loading '" + contactType + "' list of '" + profileEmail + "' over the network...");
48 |
49 | // EN: ...and return test data.
50 | //
51 | // RU: ...и возвращаем тестовые данные.
52 | Profile profile = findProfile(profileEmail);
53 | if (profile != null) {
54 | return profile.getContacts(contactType);
55 | }
56 | return null;
57 | }
58 |
59 | private Profile findProfile(String profileEmail) {
60 | for (Profile profile : profiles) {
61 | if (profile.getEmail().equals(profileEmail)) {
62 | return profile;
63 | }
64 | }
65 | return null;
66 | }
67 |
68 | private void simulateNetworkLatency() {
69 | try {
70 | Thread.sleep(2500);
71 | } catch (InterruptedException ex) {
72 | ex.printStackTrace();
73 | }
74 | }
75 |
76 | @Override
77 | public ProfileIterator createFriendsIterator(String profileEmail) {
78 | return new FacebookIterator(this, "friends", profileEmail);
79 | }
80 |
81 | @Override
82 | public ProfileIterator createCoworkersIterator(String profileEmail) {
83 | return new FacebookIterator(this, "coworkers", profileEmail);
84 | }
85 |
86 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/social_networks/LinkedIn.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.social_networks;
2 |
3 | import refactoring_guru.iterator.example.iterators.LinkedInIterator;
4 | import refactoring_guru.iterator.example.iterators.ProfileIterator;
5 | import refactoring_guru.iterator.example.profile.Profile;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class LinkedIn implements SocialNetwork {
11 | private List contacts;
12 |
13 | public LinkedIn(List cache) {
14 | if (cache != null) {
15 | this.contacts = cache;
16 | } else {
17 | this.contacts = new ArrayList<>();
18 | }
19 | }
20 |
21 | public Profile requestContactInfoFromLinkedInAPI(String profileEmail) {
22 | // EN: Here would be a POST request to one of the LinkedIn API
23 | // endpoints. Instead, we emulates long network connection, which you
24 | // would expect in the real life...
25 | //
26 | // RU: Здесь бы был POST запрос к одному из адресов API LinkedIn. Но
27 | // вместо этого мы эмулируем долгое сетевое соединение, прямо как в
28 | // реальной жизни...
29 | simulateNetworkLatency();
30 | System.out.println("LinkedIn: Loading profile '" + profileEmail + "' over the network...");
31 |
32 | // EN: ...and return test data.
33 | //
34 | // RU: ...и возвращаем тестовые данные.
35 | return findContact(profileEmail);
36 | }
37 |
38 | public List requestRelatedContactsFromLinkedInAPI(String profileEmail, String contactType) {
39 | // EN: Here would be a POST request to one of the LinkedIn API
40 | // endpoints. Instead, we emulates long network connection, which you
41 | // would expect in the real life.
42 | //
43 | // RU: Здесь бы был POST запрос к одному из адресов API LinkedIn. Но
44 | // вместо этого мы эмулируем долгое сетевое соединение, прямо как в
45 | // реальной жизни...
46 | simulateNetworkLatency();
47 | System.out.println("LinkedIn: Loading '" + contactType + "' list of '" + profileEmail + "' over the network...");
48 |
49 | // EN: ...and return test data.
50 | //
51 | // RU: ...и возвращаем тестовые данные.
52 | Profile profile = findContact(profileEmail);
53 | if (profile != null) {
54 | return profile.getContacts(contactType);
55 | }
56 | return null;
57 | }
58 |
59 | private Profile findContact(String profileEmail) {
60 | for (Profile profile : contacts) {
61 | if (profile.getEmail().equals(profileEmail)) {
62 | return profile;
63 | }
64 | }
65 | return null;
66 | }
67 |
68 | private void simulateNetworkLatency() {
69 | try {
70 | Thread.sleep(2500);
71 | } catch (InterruptedException ex) {
72 | ex.printStackTrace();
73 | }
74 | }
75 |
76 | @Override
77 | public ProfileIterator createFriendsIterator(String profileEmail) {
78 | return new LinkedInIterator(this, "friends", profileEmail);
79 | }
80 |
81 | @Override
82 | public ProfileIterator createCoworkersIterator(String profileEmail) {
83 | return new LinkedInIterator(this, "coworkers", profileEmail);
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/social_networks/SocialNetwork.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.social_networks;
2 |
3 | import refactoring_guru.iterator.example.iterators.ProfileIterator;
4 |
5 | public interface SocialNetwork {
6 | ProfileIterator createFriendsIterator(String profileEmail);
7 |
8 | ProfileIterator createCoworkersIterator(String profileEmail);
9 | }
10 |
--------------------------------------------------------------------------------
/src/refactoring_guru/iterator/example/spammer/SocialSpammer.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.iterator.example.spammer;
2 |
3 | import refactoring_guru.iterator.example.iterators.ProfileIterator;
4 | import refactoring_guru.iterator.example.profile.Profile;
5 | import refactoring_guru.iterator.example.social_networks.SocialNetwork;
6 |
7 | public class SocialSpammer {
8 | public SocialNetwork network;
9 | public ProfileIterator iterator;
10 |
11 | public SocialSpammer(SocialNetwork network) {
12 | this.network = network;
13 | }
14 |
15 | public void sendSpamToFriends(String profileEmail, String message) {
16 | System.out.println("\nIterating over friends...\n");
17 | iterator = network.createFriendsIterator(profileEmail);
18 | while (iterator.hasNext()) {
19 | Profile profile = iterator.getNext();
20 | sendMessage(profile.getEmail(), message);
21 | }
22 | }
23 |
24 | public void sendSpamToCoworkers(String profileEmail, String message) {
25 | System.out.println("\nIterating over coworkers...\n");
26 | iterator = network.createCoworkersIterator(profileEmail);
27 | while (iterator.hasNext()) {
28 | Profile profile = iterator.getNext();
29 | sendMessage(profile.getEmail(), message);
30 | }
31 | }
32 |
33 | public void sendMessage(String email, String message) {
34 | System.out.println("Sent message to: '" + email + "'. Message body: '" + message + "'");
35 | }
36 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example;
2 |
3 | import refactoring_guru.mediator.example.components.*;
4 | import refactoring_guru.mediator.example.mediator.Editor;
5 | import refactoring_guru.mediator.example.mediator.Mediator;
6 |
7 | import javax.swing.*;
8 |
9 | /**
10 | * EN: Demo class. Everything comes together here.
11 | *
12 | * RU: Демо-класс. Здесь всё сводится воедино.
13 | */
14 | public class Demo {
15 | public static void main(String[] args) {
16 | Mediator mediator = new Editor();
17 |
18 | mediator.registerComponent(new Title());
19 | mediator.registerComponent(new TextBox());
20 | mediator.registerComponent(new AddButton());
21 | mediator.registerComponent(new DeleteButton());
22 | mediator.registerComponent(new SaveButton());
23 | mediator.registerComponent(new List(new DefaultListModel()));
24 | mediator.registerComponent(new Filter());
25 |
26 | mediator.createGUI();
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/mediator/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/AddButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 | import refactoring_guru.mediator.example.mediator.Note;
5 |
6 | import javax.swing.*;
7 | import java.awt.event.ActionEvent;
8 |
9 | /**
10 | * EN: Concrete components don't talk with each other. They have only one
11 | * communication channel–sending requests to the mediator.
12 | *
13 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
14 | * один канал общения – через отправку уведомлений посреднику.
15 | */
16 | public class AddButton extends JButton implements Component {
17 | private Mediator mediator;
18 |
19 | public AddButton() {
20 | super("Add");
21 | }
22 |
23 | @Override
24 | public void setMediator(Mediator mediator) {
25 | this.mediator = mediator;
26 | }
27 |
28 | @Override
29 | protected void fireActionPerformed(ActionEvent actionEvent) {
30 | mediator.addNewNote(new Note());
31 | }
32 |
33 | @Override
34 | public String getName() {
35 | return "AddButton";
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/Component.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 |
5 | /**
6 | * EN: Common component interface.
7 | *
8 | * RU: Общий интерфейс компонентов.
9 | */
10 | public interface Component {
11 | void setMediator(Mediator mediator);
12 | String getName();
13 | }
14 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/DeleteButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 |
5 | import javax.swing.*;
6 | import java.awt.event.ActionEvent;
7 |
8 | /**
9 | * EN: Concrete components don't talk with each other. They have only one
10 | * communication channel–sending requests to the mediator.
11 | *
12 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
13 | * один канал общения – через отправку уведомлений посреднику.
14 | */
15 | public class DeleteButton extends JButton implements Component {
16 | private Mediator mediator;
17 |
18 | public DeleteButton() {
19 | super("Del");
20 | }
21 |
22 | @Override
23 | public void setMediator(Mediator mediator) {
24 | this.mediator = mediator;
25 | }
26 |
27 | @Override
28 | protected void fireActionPerformed(ActionEvent actionEvent) {
29 | mediator.deleteNote();
30 | }
31 |
32 | @Override
33 | public String getName() {
34 | return "DelButton";
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/Filter.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 | import refactoring_guru.mediator.example.mediator.Note;
5 |
6 | import javax.swing.*;
7 | import java.awt.event.KeyEvent;
8 | import java.util.ArrayList;
9 |
10 | /**
11 | * EN: Concrete components don't talk with each other. They have only one
12 | * communication channel–sending requests to the mediator.
13 | *
14 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
15 | * один канал общения – через отправку уведомлений посреднику.
16 | */
17 | public class Filter extends JTextField implements Component {
18 | private Mediator mediator;
19 | private ListModel listModel;
20 |
21 | public Filter() {}
22 |
23 | @Override
24 | public void setMediator(Mediator mediator) {
25 | this.mediator = mediator;
26 | }
27 |
28 | @Override
29 | protected void processComponentKeyEvent(KeyEvent keyEvent) {
30 | String start = getText();
31 | searchElements(start);
32 | }
33 |
34 | public void setList(ListModel listModel) {
35 | this.listModel = listModel;
36 | }
37 |
38 | private void searchElements(String s) {
39 | if (listModel == null) {
40 | return;
41 | }
42 |
43 | if (s.equals("")) {
44 | mediator.setElementsList(listModel);
45 | return;
46 | }
47 |
48 | ArrayList notes = new ArrayList<>();
49 | for (int i = 0; i < listModel.getSize(); i++) {
50 | notes.add((Note) listModel.getElementAt(i));
51 | }
52 | DefaultListModel listModel = new DefaultListModel<>();
53 | for (Note note : notes) {
54 | if (note.getName().contains(s)) {
55 | listModel.addElement(note);
56 | }
57 | }
58 | mediator.setElementsList(listModel);
59 | }
60 |
61 | @Override
62 | public String getName() {
63 | return "Filter";
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/List.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 | import refactoring_guru.mediator.example.mediator.Note;
5 |
6 | import javax.swing.*;
7 |
8 | /**
9 | * EN: Concrete components don't talk with each other. They have only one
10 | * communication channel–sending requests to the mediator.
11 | *
12 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
13 | * один канал общения – через отправку уведомлений посреднику.
14 | */
15 | @SuppressWarnings("unchecked")
16 | public class List extends JList implements Component {
17 | private Mediator mediator;
18 | private final DefaultListModel LIST_MODEL;
19 |
20 | public List(DefaultListModel listModel) {
21 | super(listModel);
22 | this.LIST_MODEL = listModel;
23 | setModel(listModel);
24 | this.setLayoutOrientation(JList.VERTICAL);
25 | Thread thread = new Thread(new Hide(this));
26 | thread.start();
27 | }
28 |
29 | @Override
30 | public void setMediator(Mediator mediator) {
31 | this.mediator = mediator;
32 | }
33 |
34 | public void addElement(Note note) {
35 | LIST_MODEL.addElement(note);
36 | int index = LIST_MODEL.size() - 1;
37 | setSelectedIndex(index);
38 | ensureIndexIsVisible(index);
39 | mediator.sendToFilter(LIST_MODEL);
40 | }
41 |
42 | public void deleteElement() {
43 | int index = this.getSelectedIndex();
44 | try {
45 | LIST_MODEL.remove(index);
46 | mediator.sendToFilter(LIST_MODEL);
47 | } catch (ArrayIndexOutOfBoundsException ignored) {}
48 | }
49 |
50 | public Note getCurrentElement() {
51 | return (Note)getSelectedValue();
52 | }
53 |
54 | @Override
55 | public String getName() {
56 | return "List";
57 | }
58 |
59 | private class Hide implements Runnable {
60 | private List list;
61 |
62 | Hide(List list) {
63 | this.list = list;
64 | }
65 |
66 | @Override
67 | public void run() {
68 | while (true) {
69 | try {
70 | Thread.sleep(300);
71 | } catch (InterruptedException ex) {
72 | ex.printStackTrace();
73 | }
74 | if (list.isSelectionEmpty()) {
75 | mediator.hideElements(true);
76 | } else {
77 | mediator.hideElements(false);
78 | }
79 | }
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/SaveButton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 |
5 | import javax.swing.*;
6 | import java.awt.event.ActionEvent;
7 |
8 | /**
9 | * EN: Concrete components don't talk with each other. They have only one
10 | * communication channel–sending requests to the mediator.
11 | *
12 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
13 | * один канал общения – через отправку уведомлений посреднику.
14 | */
15 | public class SaveButton extends JButton implements Component {
16 | private Mediator mediator;
17 |
18 | public SaveButton() {
19 | super("Save");
20 | }
21 |
22 | @Override
23 | public void setMediator(Mediator mediator) {
24 | this.mediator = mediator;
25 | }
26 |
27 | @Override
28 | protected void fireActionPerformed(ActionEvent actionEvent) {
29 | mediator.saveChanges();
30 | }
31 |
32 | @Override
33 | public String getName() {
34 | return "SaveButton";
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/TextBox.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 |
5 | import javax.swing.*;
6 | import java.awt.event.KeyEvent;
7 |
8 | /**
9 | * EN: Concrete components don't talk with each other. They have only one
10 | * communication channel–sending requests to the mediator.
11 | *
12 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
13 | * один канал общения – через отправку уведомлений посреднику.
14 | */
15 | public class TextBox extends JTextArea implements Component {
16 | private Mediator mediator;
17 |
18 | @Override
19 | public void setMediator(Mediator mediator) {
20 | this.mediator = mediator;
21 | }
22 |
23 | @Override
24 | protected void processComponentKeyEvent(KeyEvent keyEvent) {
25 | mediator.markNote();
26 | }
27 |
28 | @Override
29 | public String getName() {
30 | return "TextBox";
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/components/Title.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.components;
2 |
3 | import refactoring_guru.mediator.example.mediator.Mediator;
4 |
5 | import javax.swing.*;
6 | import java.awt.event.KeyEvent;
7 |
8 | /**
9 | * EN: Concrete components don't talk with each other. They have only one
10 | * communication channel–sending requests to the mediator.
11 | *
12 | * RU: Конкретные компоненты никак не связаны между собой. У них есть только
13 | * один канал общения – через отправку уведомлений посреднику.
14 | */
15 | public class Title extends JTextField implements Component {
16 | private Mediator mediator;
17 |
18 | @Override
19 | public void setMediator(Mediator mediator) {
20 | this.mediator = mediator;
21 | }
22 |
23 | @Override
24 | protected void processComponentKeyEvent(KeyEvent keyEvent) {
25 | mediator.markNote();
26 | }
27 |
28 | @Override
29 | public String getName() {
30 | return "Title";
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/mediator/Mediator.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.mediator;
2 |
3 | import refactoring_guru.mediator.example.components.Component;
4 |
5 | import javax.swing.*;
6 |
7 | /**
8 | * EN: Common mediator interface.
9 | *
10 | * RU: Общий интерфейс посредников.
11 | */
12 | public interface Mediator {
13 | void addNewNote(Note note);
14 | void deleteNote();
15 | void getInfoFromList(Note note);
16 | void saveChanges();
17 | void markNote();
18 | void clear();
19 | void sendToFilter(ListModel listModel);
20 | void setElementsList(ListModel list);
21 | void registerComponent(Component component);
22 | void hideElements(boolean flag);
23 | void createGUI();
24 | }
25 |
--------------------------------------------------------------------------------
/src/refactoring_guru/mediator/example/mediator/Note.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.mediator.example.mediator;
2 |
3 | /**
4 | * EN: Note class.
5 | *
6 | * RU: Класс заметок.
7 | */
8 | public class Note {
9 | private String name;
10 | private String text;
11 |
12 | public Note() {
13 | name = "New note";
14 | }
15 |
16 | public void setName(String name) {
17 | this.name = name;
18 | }
19 |
20 | public void setText(String text) {
21 | this.text = text;
22 | }
23 |
24 | public String getName() {
25 | return name;
26 | }
27 |
28 | public String getText() {
29 | return text;
30 | }
31 |
32 | @Override
33 | public String toString() {
34 | return name;
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example;
2 |
3 | import refactoring_guru.memento.example.editor.Editor;
4 | import refactoring_guru.memento.example.shapes.Circle;
5 | import refactoring_guru.memento.example.shapes.CompoundShape;
6 | import refactoring_guru.memento.example.shapes.Dot;
7 | import refactoring_guru.memento.example.shapes.Rectangle;
8 |
9 | import java.awt.*;
10 |
11 | public class Demo {
12 | public static void main(String[] args) {
13 | Editor editor = new Editor();
14 | editor.loadShapes(
15 | new Circle(10, 10, 10, Color.BLUE),
16 |
17 | new CompoundShape(
18 | new Circle(110, 110, 50, Color.RED),
19 | new Dot(160, 160, Color.RED)
20 | ),
21 |
22 | new CompoundShape(
23 | new Rectangle(250, 250, 100, 100, Color.GREEN),
24 | new Dot(240, 240, Color.GREEN),
25 | new Dot(240, 360, Color.GREEN),
26 | new Dot(360, 360, Color.GREEN),
27 | new Dot(360, 240, Color.GREEN)
28 | )
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/memento/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/commands/ColorCommand.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.commands;
2 |
3 | import refactoring_guru.memento.example.editor.Editor;
4 | import refactoring_guru.memento.example.shapes.Shape;
5 |
6 | import java.awt.*;
7 |
8 | public class ColorCommand implements Command {
9 | private Editor editor;
10 | private Color color;
11 |
12 | public ColorCommand(Editor editor, Color color) {
13 | this.editor = editor;
14 | this.color = color;
15 | }
16 |
17 | @Override
18 | public String getName() {
19 | return "Colorize: " + color.toString();
20 | }
21 |
22 | @Override
23 | public void execute() {
24 | for (Shape child : editor.getShapes().getSelected()) {
25 | child.setColor(color);
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/commands/Command.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.commands;
2 |
3 | public interface Command {
4 | String getName();
5 | void execute();
6 | }
7 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/commands/MoveCommand.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.commands;
2 |
3 | import refactoring_guru.memento.example.editor.Editor;
4 | import refactoring_guru.memento.example.shapes.Shape;
5 |
6 | public class MoveCommand implements Command {
7 | private Editor editor;
8 | private int startX, startY;
9 | private int endX, endY;
10 |
11 | public MoveCommand(Editor editor) {
12 | this.editor = editor;
13 | }
14 |
15 | @Override
16 | public String getName() {
17 | return "Move by X:" + (endX - startX) + " Y:" + (endY - startY);
18 | }
19 |
20 | public void start(int x, int y) {
21 | startX = x;
22 | startY = y;
23 | for (Shape child : editor.getShapes().getSelected()) {
24 | child.drag();
25 | }
26 | }
27 |
28 | public void move(int x, int y) {
29 | for (Shape child : editor.getShapes().getSelected()) {
30 | child.moveTo(x - startX, y - startY);
31 | }
32 | }
33 |
34 | public void stop(int x, int y) {
35 | endX = x;
36 | endY = y;
37 | for (Shape child : editor.getShapes().getSelected()) {
38 | child.drop();
39 | }
40 | }
41 |
42 | @Override
43 | public void execute() {
44 | for (Shape child : editor.getShapes().getSelected()) {
45 | child.moveBy(endX - startX, endY - startY);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/editor/Editor.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.editor;
2 |
3 | import refactoring_guru.memento.example.commands.Command;
4 | import refactoring_guru.memento.example.history.History;
5 | import refactoring_guru.memento.example.history.Memento;
6 | import refactoring_guru.memento.example.shapes.CompoundShape;
7 | import refactoring_guru.memento.example.shapes.Shape;
8 |
9 | import javax.swing.*;
10 | import java.io.*;
11 | import java.util.Base64;
12 |
13 | public class Editor extends JComponent {
14 | private Canvas canvas;
15 | private CompoundShape allShapes = new CompoundShape();
16 | private History history;
17 |
18 | public Editor() {
19 | canvas = new Canvas(this);
20 | history = new History();
21 | }
22 |
23 | public void loadShapes(Shape... shapes) {
24 | allShapes.clear();
25 | allShapes.add(shapes);
26 | canvas.refresh();
27 | }
28 |
29 | public CompoundShape getShapes() {
30 | return allShapes;
31 | }
32 |
33 | public void execute(Command c) {
34 | history.push(c, new Memento(this));
35 | c.execute();
36 | }
37 |
38 | public void undo() {
39 | if (history.undo())
40 | canvas.repaint();
41 | }
42 |
43 | public void redo() {
44 | if (history.redo())
45 | canvas.repaint();
46 | }
47 |
48 | public String backup() {
49 | try {
50 | ByteArrayOutputStream baos = new ByteArrayOutputStream();
51 | ObjectOutputStream oos = new ObjectOutputStream(baos);
52 | oos.writeObject(this.allShapes);
53 | oos.close();
54 | return Base64.getEncoder().encodeToString(baos.toByteArray());
55 | } catch (IOException e) {
56 | return "";
57 | }
58 | }
59 |
60 | public void restore(String state) {
61 | try {
62 | byte[] data = Base64.getDecoder().decode(state);
63 | ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(data));
64 | this.allShapes = (CompoundShape) ois.readObject();
65 | ois.close();
66 | } catch (ClassNotFoundException e) {
67 | System.out.print("ClassNotFoundException occurred.");
68 | } catch (IOException e) {
69 | System.out.print("IOException occurred.");
70 | }
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/history/History.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.history;
2 |
3 | import refactoring_guru.memento.example.commands.Command;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class History {
9 | private List history = new ArrayList();
10 | private int virtualSize = 0;
11 |
12 | private class Pair {
13 | Command command;
14 | Memento memento;
15 | Pair(Command c, Memento m) {
16 | command = c;
17 | memento = m;
18 | }
19 |
20 | private Command getCommand() {
21 | return command;
22 | }
23 |
24 | private Memento getMemento() {
25 | return memento;
26 | }
27 | }
28 |
29 | public void push(Command c, Memento m) {
30 | if (virtualSize != history.size() && virtualSize > 0) {
31 | history = history.subList(0, virtualSize - 1);
32 | }
33 | history.add(new Pair(c, m));
34 | virtualSize = history.size();
35 | }
36 |
37 | public boolean undo() {
38 | Pair pair = getUndo();
39 | if (pair == null) {
40 | return false;
41 | }
42 | System.out.println("Undoing: " + pair.getCommand().getName());
43 | pair.getMemento().restore();
44 | return true;
45 | }
46 |
47 | public boolean redo() {
48 | Pair pair = getRedo();
49 | if (pair == null) {
50 | return false;
51 | }
52 | System.out.println("Redoing: " + pair.getCommand().getName());
53 | pair.getMemento().restore();
54 | pair.getCommand().execute();
55 | return true;
56 | }
57 |
58 | private Pair getUndo() {
59 | if (virtualSize == 0) {
60 | return null;
61 | }
62 | virtualSize = Math.max(0, virtualSize - 1);
63 | return history.get(virtualSize);
64 | }
65 |
66 | private Pair getRedo() {
67 | if (virtualSize == history.size()) {
68 | return null;
69 | }
70 | virtualSize = Math.min(history.size(), virtualSize + 1);
71 | return history.get(virtualSize - 1);
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/history/Memento.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.history;
2 |
3 | import refactoring_guru.memento.example.editor.Editor;
4 |
5 | public class Memento {
6 | private String backup;
7 | private Editor editor;
8 |
9 | public Memento(Editor editor) {
10 | this.editor = editor;
11 | this.backup = editor.backup();
12 | }
13 |
14 | public void restore() {
15 | editor.restore(backup);
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/shapes/BaseShape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public abstract class BaseShape implements Shape {
6 | int x, y;
7 | private int dx = 0, dy = 0;
8 | private Color color;
9 | private boolean selected = false;
10 |
11 | BaseShape(int x, int y, Color color) {
12 | this.x = x;
13 | this.y = y;
14 | this.color = color;
15 | }
16 |
17 | @Override
18 | public int getX() {
19 | return x;
20 | }
21 |
22 | @Override
23 | public int getY() {
24 | return y;
25 | }
26 |
27 | @Override
28 | public int getWidth() {
29 | return 0;
30 | }
31 |
32 | @Override
33 | public int getHeight() {
34 | return 0;
35 | }
36 |
37 | @Override
38 | public void drag() {
39 | dx = x;
40 | dy = y;
41 | }
42 |
43 | @Override
44 | public void moveTo(int x, int y) {
45 | this.x = dx + x;
46 | this.y = dy + y;
47 | }
48 |
49 | @Override
50 | public void moveBy(int x, int y) {
51 | this.x += x;
52 | this.y += y;
53 | }
54 |
55 | @Override
56 | public void drop() {
57 | this.x = dx;
58 | this.y = dy;
59 | }
60 |
61 | @Override
62 | public boolean isInsideBounds(int x, int y) {
63 | return x > getX() && x < (getX() + getWidth()) &&
64 | y > getY() && y < (getY() + getHeight());
65 | }
66 |
67 | @Override
68 | public Color getColor() {
69 | return color;
70 | }
71 |
72 | @Override
73 | public void setColor(Color color) {
74 | this.color = color;
75 | }
76 |
77 | @Override
78 | public void select() {
79 | selected = true;
80 | }
81 |
82 | @Override
83 | public void unSelect() {
84 | selected = false;
85 | }
86 |
87 | @Override
88 | public boolean isSelected() {
89 | return selected;
90 | }
91 |
92 | void enableSelectionStyle(Graphics graphics) {
93 | graphics.setColor(Color.LIGHT_GRAY);
94 |
95 | Graphics2D g2 = (Graphics2D) graphics;
96 | float[] dash1 = {2.0f};
97 | g2.setStroke(new BasicStroke(1.0f,
98 | BasicStroke.CAP_BUTT,
99 | BasicStroke.JOIN_MITER,
100 | 2.0f, dash1, 0.0f));
101 | }
102 |
103 | void disableSelectionStyle(Graphics graphics) {
104 | graphics.setColor(color);
105 | Graphics2D g2 = (Graphics2D) graphics;
106 | g2.setStroke(new BasicStroke());
107 | }
108 |
109 | @Override
110 | public void paint(Graphics graphics) {
111 | if (isSelected()) {
112 | enableSelectionStyle(graphics);
113 | }
114 | else {
115 | disableSelectionStyle(graphics);
116 | }
117 |
118 | // ...
119 | }
120 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/shapes/Circle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public class Circle extends BaseShape {
6 | private int radius;
7 |
8 | public Circle(int x, int y, int radius, Color color) {
9 | super(x, y, color);
10 | this.radius = radius;
11 | }
12 |
13 | @Override
14 | public int getWidth() {
15 | return radius * 2;
16 | }
17 |
18 | @Override
19 | public int getHeight() {
20 | return radius * 2;
21 | }
22 |
23 | @Override
24 | public void paint(Graphics graphics) {
25 | super.paint(graphics);
26 | graphics.drawOval(x, y, getWidth() - 1, getHeight() - 1);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/shapes/Dot.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public class Dot extends BaseShape {
6 | private final int DOT_SIZE = 3;
7 |
8 | public Dot(int x, int y, Color color) {
9 | super(x, y, color);
10 | }
11 |
12 | @Override
13 | public int getWidth() {
14 | return DOT_SIZE;
15 | }
16 |
17 | @Override
18 | public int getHeight() {
19 | return DOT_SIZE;
20 | }
21 |
22 | @Override
23 | public void paint(Graphics graphics) {
24 | super.paint(graphics);
25 | graphics.fillRect(x - 1, y - 1, getWidth(), getHeight());
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/shapes/Rectangle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.shapes;
2 |
3 | import java.awt.*;
4 |
5 | public class Rectangle extends BaseShape {
6 | private int width;
7 | private int height;
8 |
9 | public Rectangle(int x, int y, int width, int height, Color color) {
10 | super(x, y, color);
11 | this.width = width;
12 | this.height = height;
13 | }
14 |
15 | @Override
16 | public int getWidth() {
17 | return width;
18 | }
19 |
20 | @Override
21 | public int getHeight() {
22 | return height;
23 | }
24 |
25 | @Override
26 | public void paint(Graphics graphics) {
27 | super.paint(graphics);
28 | graphics.drawRect(x, y, getWidth() - 1, getHeight() - 1);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/src/refactoring_guru/memento/example/shapes/Shape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.memento.example.shapes;
2 |
3 | import java.awt.*;
4 | import java.io.Serializable;
5 |
6 | public interface Shape extends Serializable {
7 | int getX();
8 | int getY();
9 | int getWidth();
10 | int getHeight();
11 | void drag();
12 | void drop();
13 | void moveTo(int x, int y);
14 | void moveBy(int x, int y);
15 | boolean isInsideBounds(int x, int y);
16 | Color getColor();
17 | void setColor(Color color);
18 | void select();
19 | void unSelect();
20 | boolean isSelected();
21 | void paint(Graphics graphics);
22 | }
23 |
24 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.observer.example;
2 |
3 | import refactoring_guru.observer.example.editor.Editor;
4 | import refactoring_guru.observer.example.listeners.EmailNotificationListener;
5 | import refactoring_guru.observer.example.listeners.LogOpenListener;
6 |
7 | public class Demo {
8 | public static void main(String[] args) {
9 | Editor editor = new Editor();
10 | editor.events.subscribe("open", new LogOpenListener("/path/to/log/file.txt"));
11 | editor.events.subscribe("save", new EmailNotificationListener("admin@example.com"));
12 |
13 | try {
14 | editor.openFile("test.txt");
15 | editor.saveFile();
16 | } catch (Exception e) {
17 | e.printStackTrace();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Save to log \path\to\log\file.txt: Someone has performed open operation with the following file: test.txt
2 | Email to admin@example.com: Someone has performed save operation with the following file: test.txt
3 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/editor/Editor.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.observer.example.editor;
2 |
3 | import refactoring_guru.observer.example.publisher.EventManager;
4 |
5 | import java.io.File;
6 |
7 | public class Editor {
8 | public EventManager events;
9 | private File file;
10 |
11 | public Editor() {
12 | this.events = new EventManager("open", "save");
13 | }
14 |
15 | public void openFile(String filePath) {
16 | this.file = new File(filePath);
17 | events.notify("open", file);
18 | }
19 |
20 | public void saveFile() throws Exception {
21 | if (this.file != null) {
22 | events.notify("save", file);
23 | } else {
24 | throw new Exception("Please open a file first.");
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/listeners/EmailNotificationListener.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.observer.example.listeners;
2 |
3 | import java.io.File;
4 |
5 | public class EmailNotificationListener implements EventListener {
6 | private String email;
7 |
8 | public EmailNotificationListener(String email) {
9 | this.email = email;
10 | }
11 |
12 | @Override
13 | public void update(String eventType, File file) {
14 | System.out.println("Email to " + email + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/listeners/EventListener.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.observer.example.listeners;
2 |
3 | import java.io.File;
4 |
5 | public interface EventListener {
6 | void update(String eventType, File file);
7 | }
8 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/listeners/LogOpenListener.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.observer.example.listeners;
2 |
3 | import java.io.File;
4 |
5 | public class LogOpenListener implements EventListener {
6 | private File log;
7 |
8 | public LogOpenListener(String fileName) {
9 | this.log = new File(fileName);
10 | }
11 |
12 | @Override
13 | public void update(String eventType, File file) {
14 | System.out.println("Save to log " + log + ": Someone has performed " + eventType + " operation with the following file: " + file.getName());
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/src/refactoring_guru/observer/example/publisher/EventManager.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.observer.example.publisher;
2 |
3 | import refactoring_guru.observer.example.listeners.EventListener;
4 |
5 | import java.io.File;
6 | import java.util.ArrayList;
7 | import java.util.HashMap;
8 | import java.util.List;
9 | import java.util.Map;
10 |
11 | public class EventManager {
12 | Map> listeners = new HashMap<>();
13 |
14 | public EventManager(String... operations) {
15 | for (String operation : operations) {
16 | this.listeners.put(operation, new ArrayList<>());
17 | }
18 | }
19 |
20 | public void subscribe(String eventType, EventListener listener) {
21 | List users = listeners.get(eventType);
22 | users.add(listener);
23 | }
24 |
25 | public void unsubscribe(String eventType, EventListener listener) {
26 | List users = listeners.get(eventType);
27 | users.remove(listener);
28 | }
29 |
30 | public void notify(String eventType, File file) {
31 | List users = listeners.get(eventType);
32 | for (EventListener listener : users) {
33 | listener.update(eventType, file);
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/caching/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.prototype.caching;
2 |
3 | import refactoring_guru.prototype.caching.cache.BundledShapeCache;
4 | import refactoring_guru.prototype.example.shapes.Shape;
5 |
6 | public class Demo {
7 | public static void main(String[] args) {
8 | BundledShapeCache cache = new BundledShapeCache();
9 |
10 | Shape shape1 = cache.get("Big green circle");
11 | Shape shape2 = cache.get("Medium blue rectangle");
12 | Shape shape3 = cache.get("Medium blue rectangle");
13 |
14 | if (shape1 != shape2 && !shape1.equals(shape2)) {
15 | System.out.println("Big green circle != Medium blue rectangle (yay!)");
16 | } else {
17 | System.out.println("Big green circle == Medium blue rectangle (booo!)");
18 | }
19 |
20 | if (shape2 != shape3) {
21 | System.out.println("Medium blue rectangles are two different objects (yay!)");
22 | if (shape2.equals(shape3)) {
23 | System.out.println("And they are identical (yay!)");
24 | } else {
25 | System.out.println("But they are not identical (booo!)");
26 | }
27 | } else {
28 | System.out.println("Rectangle objects are the same (booo!)");
29 | }
30 | }
31 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/caching/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Big green circle != Medium blue rectangle (yay!)
2 | Medium blue rectangles are two different objects (yay!)
3 | And they are identical (yay!)
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/caching/cache/BundledShapeCache.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.prototype.caching.cache;
2 |
3 | import refactoring_guru.prototype.example.shapes.Circle;
4 | import refactoring_guru.prototype.example.shapes.Rectangle;
5 | import refactoring_guru.prototype.example.shapes.Shape;
6 |
7 | import java.util.HashMap;
8 | import java.util.Map;
9 |
10 | public class BundledShapeCache {
11 | private Map cache = new HashMap<>();
12 |
13 | public BundledShapeCache() {
14 | Circle circle = new Circle();
15 | circle.x = 5;
16 | circle.y = 7;
17 | circle.radius = 45;
18 | circle.color = "Green";
19 |
20 | Rectangle rectangle = new Rectangle();
21 | rectangle.x = 6;
22 | rectangle.y = 9;
23 | rectangle.width = 8;
24 | rectangle.height = 10;
25 | rectangle.color = "Blue";
26 |
27 | cache.put("Big green circle", circle);
28 | cache.put("Medium blue rectangle", rectangle);
29 | }
30 |
31 | public Shape put(String key, Shape shape) {
32 | cache.put(key, shape);
33 | return shape;
34 | }
35 |
36 | public Shape get(String key) {
37 | return cache.get(key).clone();
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.prototype.example;
2 |
3 | import refactoring_guru.prototype.example.shapes.Circle;
4 | import refactoring_guru.prototype.example.shapes.Rectangle;
5 | import refactoring_guru.prototype.example.shapes.Shape;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | public class Demo {
11 | public static void main(String[] args) {
12 | List shapes = new ArrayList<>();
13 | List shapesCopy = new ArrayList<>();
14 |
15 | Circle circle = new Circle();
16 | circle.x = 10;
17 | circle.y = 20;
18 | circle.radius = 15;
19 | circle.color = "red";
20 | shapes.add(circle);
21 |
22 | Circle anotherCircle = (Circle) circle.clone();
23 | shapes.add(anotherCircle);
24 |
25 | Rectangle rectangle = new Rectangle();
26 | rectangle.width = 10;
27 | rectangle.height = 20;
28 | rectangle.color = "blue";
29 | shapes.add(rectangle);
30 |
31 | cloneAndCompare(shapes, shapesCopy);
32 | }
33 |
34 | private static void cloneAndCompare(List shapes, List shapesCopy) {
35 | for (Shape shape : shapes) {
36 | shapesCopy.add(shape.clone());
37 | }
38 |
39 | for (int i = 0; i < shapes.size(); i++) {
40 | if (shapes.get(i) != shapesCopy.get(i)) {
41 | System.out.println(i + ": Shapes are different objects (yay!)");
42 | if (shapes.get(i).equals(shapesCopy.get(i))) {
43 | System.out.println(i + ": And they are identical (yay!)");
44 | } else {
45 | System.out.println(i + ": But they are not identical (booo!)");
46 | }
47 | } else {
48 | System.out.println(i + ": Shape objects are the same (booo!)");
49 | }
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | 0: Shapes are different objects (yay!)
2 | 0: And they are identical (yay!)
3 | 1: Shapes are different objects (yay!)
4 | 1: And they are identical (yay!)
5 | 2: Shapes are different objects (yay!)
6 | 2: And they are identical (yay!)
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/example/shapes/Circle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.prototype.example.shapes;
2 |
3 | public class Circle extends Shape {
4 | public int radius;
5 |
6 | public Circle() {
7 | }
8 |
9 | public Circle(Circle target) {
10 | super(target);
11 | if (target != null) {
12 | this.radius = target.radius;
13 | }
14 | }
15 |
16 | @Override
17 | public Shape clone() {
18 | return new Circle(this);
19 | }
20 |
21 | @Override
22 | public boolean equals(Object object2) {
23 | if (!(object2 instanceof Circle) || !super.equals(object2)) return false;
24 | Circle shape2 = (Circle) object2;
25 | return shape2.radius == radius;
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/example/shapes/Rectangle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.prototype.example.shapes;
2 |
3 | public class Rectangle extends Shape {
4 | public int width;
5 | public int height;
6 |
7 | public Rectangle() {
8 | }
9 |
10 | public Rectangle(Rectangle target) {
11 | super(target);
12 | if (target != null) {
13 | this.width = target.width;
14 | this.height = target.height;
15 | }
16 | }
17 |
18 | @Override
19 | public Shape clone() {
20 | return new Rectangle(this);
21 | }
22 |
23 | @Override
24 | public boolean equals(Object object2) {
25 | if (!(object2 instanceof Rectangle) || !super.equals(object2)) return false;
26 | Rectangle shape2 = (Rectangle) object2;
27 | return shape2.width == width && shape2.height == height;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/prototype/example/shapes/Shape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.prototype.example.shapes;
2 |
3 | import java.util.Objects;
4 |
5 | public abstract class Shape {
6 | public int x;
7 | public int y;
8 | public String color;
9 |
10 | public Shape() {
11 | }
12 |
13 | public Shape(Shape target) {
14 | if (target != null) {
15 | this.x = target.x;
16 | this.y = target.y;
17 | this.color = target.color;
18 | }
19 | }
20 |
21 | public abstract Shape clone();
22 |
23 | @Override
24 | public boolean equals(Object object2) {
25 | if (!(object2 instanceof Shape)) return false;
26 | Shape shape2 = (Shape) object2;
27 | return shape2.x == x && shape2.y == y && Objects.equals(shape2.color, color);
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/proxy/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.proxy.example;
2 |
3 | import refactoring_guru.proxy.example.downloader.YouTubeDownloader;
4 | import refactoring_guru.proxy.example.proxy.YouTubeCacheProxy;
5 | import refactoring_guru.proxy.example.some_cool_media_library.ThirdPartyYouTubeClass;
6 |
7 | public class Demo {
8 |
9 | public static void main(String[] args) {
10 | YouTubeDownloader naiveDownloader = new YouTubeDownloader(new ThirdPartyYouTubeClass());
11 | YouTubeDownloader smartDownloader = new YouTubeDownloader(new YouTubeCacheProxy());
12 |
13 | long naive = test(naiveDownloader);
14 | long smart = test(smartDownloader);
15 | System.out.print("Time saved by caching proxy: " + (naive - smart) + "ms");
16 |
17 | }
18 |
19 | private static long test(YouTubeDownloader downloader) {
20 | long startTime = System.currentTimeMillis();
21 |
22 | // User behavior in our app:
23 | downloader.renderPopularVideos();
24 | downloader.renderVideoPage("catzzzzzzzzz");
25 | downloader.renderPopularVideos();
26 | downloader.renderVideoPage("dancesvideoo");
27 | // Users might visit the same page quite often.
28 | downloader.renderVideoPage("catzzzzzzzzz");
29 | downloader.renderVideoPage("someothervid");
30 |
31 | long estimatedTime = System.currentTimeMillis() - startTime;
32 | System.out.print("Time elapsed: " + estimatedTime + "ms\n");
33 | return estimatedTime;
34 | }
35 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/proxy/example/downloader/YouTubeDownloader.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.proxy.example.downloader;
2 |
3 | import refactoring_guru.proxy.example.some_cool_media_library.ThirdPartyYouTubeLib;
4 | import refactoring_guru.proxy.example.some_cool_media_library.Video;
5 |
6 | import java.util.HashMap;
7 |
8 | public class YouTubeDownloader {
9 | private ThirdPartyYouTubeLib api;
10 |
11 | public YouTubeDownloader(ThirdPartyYouTubeLib api) {
12 | this.api = api;
13 | }
14 |
15 | public void renderVideoPage(String videoId) {
16 | Video video = api.getVideo(videoId);
17 | System.out.println("\n-------------------------------");
18 | System.out.println("Video page (imagine fancy HTML)");
19 | System.out.println("ID: " + video.id);
20 | System.out.println("Title: " + video.title);
21 | System.out.println("Video: " + video.data);
22 | System.out.println("-------------------------------\n");
23 | }
24 |
25 | public void renderPopularVideos() {
26 | HashMap list = api.popularVideos();
27 | System.out.println("\n-------------------------------");
28 | System.out.println("Most popular videos on YouTube (imagine fancy HTML)");
29 | for (Video video : list.values()) {
30 | System.out.println("ID: " + video.id + " / Title: " + video.title);
31 | }
32 | System.out.println("-------------------------------\n");
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/refactoring_guru/proxy/example/proxy/YouTubeCacheProxy.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.proxy.example.proxy;
2 |
3 | import refactoring_guru.proxy.example.some_cool_media_library.ThirdPartyYouTubeClass;
4 | import refactoring_guru.proxy.example.some_cool_media_library.ThirdPartyYouTubeLib;
5 | import refactoring_guru.proxy.example.some_cool_media_library.Video;
6 |
7 | import java.util.HashMap;
8 |
9 | public class YouTubeCacheProxy implements ThirdPartyYouTubeLib {
10 | private ThirdPartyYouTubeLib youtubeService;
11 | private HashMap cachePopular = new HashMap();
12 | private HashMap cacheAll = new HashMap();
13 |
14 | public YouTubeCacheProxy() {
15 | this.youtubeService = new ThirdPartyYouTubeClass();
16 | }
17 |
18 | @Override
19 | public HashMap popularVideos() {
20 | if (cachePopular.isEmpty()) {
21 | cachePopular = youtubeService.popularVideos();
22 | } else {
23 | System.out.println("Retrieved list from cache.");
24 | }
25 | return cachePopular;
26 | }
27 |
28 | @Override
29 | public Video getVideo(String videoId) {
30 | Video video = cacheAll.get(videoId);
31 | if (video == null) {
32 | video = youtubeService.getVideo(videoId);
33 | cacheAll.put(videoId, video);
34 | } else {
35 | System.out.println("Retrieved video '" + videoId + "' from cache.");
36 | }
37 | return video;
38 | }
39 |
40 | public void reset() {
41 | cachePopular.clear();
42 | cacheAll.clear();
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/refactoring_guru/proxy/example/some_cool_media_library/ThirdPartyYouTubeClass.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.proxy.example.some_cool_media_library;
2 |
3 | import java.util.HashMap;
4 |
5 | public class ThirdPartyYouTubeClass implements ThirdPartyYouTubeLib {
6 |
7 | @Override
8 | public HashMap popularVideos() {
9 | connectToServer("http://www.youtube.com");
10 | return getRandomVideos();
11 | }
12 |
13 | @Override
14 | public Video getVideo(String videoId) {
15 | connectToServer("http://www.youtube.com/" + videoId);
16 | return getSomeVideo(videoId);
17 | }
18 |
19 | // -----------------------------------------------------------------------
20 | // Fake methods to simulate network activity. They as slow as a real life.
21 |
22 | private int random(int min, int max) {
23 | return min + (int) (Math.random() * ((max - min) + 1));
24 | }
25 |
26 | private void experienceNetworkLatency() {
27 | int randomLatency = random(5, 10);
28 | for (int i = 0; i < randomLatency; i++) {
29 | try {
30 | Thread.sleep(100);
31 | } catch (InterruptedException ex) {
32 | ex.printStackTrace();
33 | }
34 | }
35 | }
36 |
37 | private void connectToServer(String server) {
38 | System.out.print("Connecting to " + server + "... ");
39 | experienceNetworkLatency();
40 | System.out.print("Connected!" + "\n");
41 | }
42 |
43 | private HashMap getRandomVideos() {
44 | System.out.print("Downloading populars... ");
45 |
46 | experienceNetworkLatency();
47 | HashMap hmap = new HashMap();
48 | hmap.put("catzzzzzzzzz", new Video("sadgahasgdas", "Catzzzz.avi"));
49 | hmap.put("mkafksangasj", new Video("mkafksangasj", "Dog play with ball.mp4"));
50 | hmap.put("dancesvideoo", new Video("asdfas3ffasd", "Dancing video.mpq"));
51 | hmap.put("dlsdk5jfslaf", new Video("dlsdk5jfslaf", "Barcelona vs RealM.mov"));
52 | hmap.put("3sdfgsd1j333", new Video("3sdfgsd1j333", "Programing lesson#1.avi"));
53 |
54 | System.out.print("Done!" + "\n");
55 | return hmap;
56 | }
57 |
58 | private Video getSomeVideo(String videoId) {
59 | System.out.print("Downloading video... ");
60 |
61 | experienceNetworkLatency();
62 | Video video = new Video(videoId, "Some video title");
63 |
64 | System.out.print("Done!" + "\n");
65 | return video;
66 | }
67 |
68 | }
69 |
--------------------------------------------------------------------------------
/src/refactoring_guru/proxy/example/some_cool_media_library/ThirdPartyYouTubeLib.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.proxy.example.some_cool_media_library;
2 |
3 | import java.util.HashMap;
4 |
5 | public interface ThirdPartyYouTubeLib {
6 | HashMap popularVideos();
7 |
8 | Video getVideo(String videoId);
9 | }
10 |
--------------------------------------------------------------------------------
/src/refactoring_guru/proxy/example/some_cool_media_library/Video.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.proxy.example.some_cool_media_library;
2 |
3 | public class Video {
4 | public String id;
5 | public String title;
6 | public String data;
7 |
8 | Video(String id, String title) {
9 | this.id = id;
10 | this.title = title;
11 | this.data = "Random video.";
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/non_thread_safe/DemoMultiThread.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.singleton.example.non_thread_safe;
2 |
3 | public class DemoMultiThread {
4 | public static void main(String[] args) {
5 | System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
6 | "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
7 | "RESULT:" + "\n");
8 | Thread threadFoo = new Thread(new ThreadFoo());
9 | Thread threadBar = new Thread(new ThreadBar());
10 | threadFoo.start();
11 | threadBar.start();
12 | }
13 |
14 | static class ThreadFoo implements Runnable {
15 | @Override
16 | public void run() {
17 | Singleton singleton = Singleton.getInstance("FOO");
18 | System.out.println(singleton.value);
19 | }
20 | }
21 |
22 | static class ThreadBar implements Runnable {
23 | @Override
24 | public void run() {
25 | Singleton singleton = Singleton.getInstance("BAR");
26 | System.out.println(singleton.value);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/non_thread_safe/DemoSingleThread.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.singleton.example.non_thread_safe;
2 |
3 | public class DemoSingleThread {
4 | public static void main(String[] args) {
5 | System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
6 | "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
7 | "RESULT:" + "\n");
8 | Singleton singleton = Singleton.getInstance("FOO");
9 | Singleton anotherSingleton = Singleton.getInstance("BAR");
10 | System.out.println(singleton.value);
11 | System.out.println(anotherSingleton.value);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/non_thread_safe/OutputDemoMultiThread.txt:
--------------------------------------------------------------------------------
1 | If you see the same value, then singleton was reused (yay!)
2 | If you see different values, then 2 singletons were created (booo!!)
3 |
4 | RESULT:
5 |
6 | FOO
7 | BAR
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/non_thread_safe/OutputDemoSingleThread.txt:
--------------------------------------------------------------------------------
1 | If you see the same value, then singleton was reused (yay!)
2 | If you see different values, then 2 singletons were created (booo!!)
3 |
4 | RESULT:
5 |
6 | FOO
7 | FOO
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/non_thread_safe/Singleton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.singleton.example.non_thread_safe;
2 |
3 | public final class Singleton {
4 | private static Singleton instance;
5 | public String value;
6 |
7 | private Singleton(String value) {
8 | // EN: The following code emulates slow initialization.
9 | //
10 | // RU: Этот код эмулирует медленную инициализацию.
11 | try {
12 | Thread.sleep(1000);
13 | } catch (InterruptedException ex) {
14 | ex.printStackTrace();
15 | }
16 | this.value = value;
17 | }
18 |
19 | public static Singleton getInstance(String value) {
20 | if (instance == null) {
21 | instance = new Singleton(value);
22 | }
23 | return instance;
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/thread_safe/DemoMultiThread.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.singleton.example.thread_safe;
2 |
3 | public class DemoMultiThread {
4 | public static void main(String[] args) {
5 | System.out.println("If you see the same value, then singleton was reused (yay!)" + "\n" +
6 | "If you see different values, then 2 singletons were created (booo!!)" + "\n\n" +
7 | "RESULT:" + "\n");
8 | Thread threadFoo = new Thread(new ThreadFoo());
9 | Thread threadBar = new Thread(new ThreadBar());
10 | threadFoo.start();
11 | threadBar.start();
12 | }
13 |
14 | static class ThreadFoo implements Runnable {
15 | @Override
16 | public void run() {
17 | Singleton singleton = Singleton.getInstance("FOO");
18 | System.out.println(singleton.value);
19 | }
20 | }
21 |
22 | static class ThreadBar implements Runnable {
23 | @Override
24 | public void run() {
25 | Singleton singleton = Singleton.getInstance("BAR");
26 | System.out.println(singleton.value);
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/thread_safe/OutputDemoMultiThread.txt:
--------------------------------------------------------------------------------
1 | If you see the same value, then singleton was reused (yay!)
2 | If you see different values, then 2 singletons were created (booo!!)
3 |
4 | RESULT:
5 |
6 | BAR
7 | BAR
--------------------------------------------------------------------------------
/src/refactoring_guru/singleton/example/thread_safe/Singleton.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.singleton.example.thread_safe;
2 |
3 | public final class Singleton {
4 | // EN: The field must be declared volatile so that double check lock would
5 | // work correctly.
6 | //
7 | // RU: Поле обязательно должно быть объявлено volatile, чтобы двойная
8 | // проверка блокировки сработала как надо.
9 | private static volatile Singleton instance;
10 |
11 | public String value;
12 |
13 | private Singleton(String value) {
14 | this.value = value;
15 | }
16 |
17 | public static Singleton getInstance(String value) {
18 | // EN: The approach taken here is called double-checked locking (DCL).
19 | // It exists to prevent race condition between multiple threads that may
20 | // attempt to get singleton instance at the same time, creating
21 | // separate instances as a result.
22 | //
23 | // It may seem that having the `result` variable here is completely
24 | // pointless. There is, however, a very important caveat when
25 | // implementing double-checked locking in Java, which is solved by
26 | // introducing this local variable.
27 | //
28 | // You can read more info DCL issues in Java here:
29 | // https://refactoring.guru/java-dcl-issue
30 | //
31 | // RU: Техника, которую мы здесь применяем называется «блокировка с
32 | // двойной проверкой» (Double-Checked Locking). Она применяется, чтобы
33 | // предотвратить создание нескольких объектов-одиночек, если метод будет
34 | // вызван из нескольких потоков одновременно.
35 | //
36 | // Хотя переменная `result` вполне оправданно кажется здесь лишней, она
37 | // помогает избежать подводных камней реализации DCL в Java.
38 | //
39 | // Больше об этой проблеме можно почитать здесь:
40 | // https://refactoring.guru/ru/java-dcl-issue
41 | Singleton result = instance;
42 | if (result != null) {
43 | return result;
44 | }
45 | synchronized(Singleton.class) {
46 | if (instance == null) {
47 | instance = new Singleton(value);
48 | }
49 | return instance;
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example;
2 |
3 | import refactoring_guru.state.example.ui.Player;
4 | import refactoring_guru.state.example.ui.UI;
5 |
6 | /**
7 | * EN: Demo class. Everything comes together here.
8 | *
9 | * RU: Демо-класс. Здесь всё сводится воедино.
10 | */
11 | public class Demo {
12 | public static void main(String[] args) {
13 | Player player = new Player();
14 | UI ui = new UI(player);
15 | ui.init();
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/OutputDemo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/RefactoringGuru/design-patterns-java/6ed6a34e22020d13c088d5aff10d1752700fca06/src/refactoring_guru/state/example/OutputDemo.png
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/states/LockedState.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example.states;
2 |
3 | import refactoring_guru.state.example.ui.Player;
4 |
5 | /**
6 | * EN: Concrete states provide the special implementation for all interface
7 | * methods.
8 | *
9 | * RU: Конкретные состояния реализуют методы абстрактного состояния по-своему.
10 | */
11 | public class LockedState extends State {
12 |
13 | LockedState(Player player) {
14 | super(player);
15 | player.setPlaying(false);
16 | }
17 |
18 | @Override
19 | public String onLock() {
20 | if (player.isPlaying()) {
21 | player.changeState(new ReadyState(player));
22 | return "Stop playing";
23 | } else {
24 | return "Locked...";
25 | }
26 | }
27 |
28 | @Override
29 | public String onPlay() {
30 | player.changeState(new ReadyState(player));
31 | return "Ready";
32 | }
33 |
34 | @Override
35 | public String onNext() {
36 | return "Locked...";
37 | }
38 |
39 | @Override
40 | public String onPrevious() {
41 | return "Locked...";
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/states/PlayingState.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example.states;
2 |
3 | import refactoring_guru.state.example.ui.Player;
4 |
5 | public class PlayingState extends State {
6 |
7 | PlayingState(Player player) {
8 | super(player);
9 | }
10 |
11 | @Override
12 | public String onLock() {
13 | player.changeState(new LockedState(player));
14 | player.setCurrentTrackAfterStop();
15 | return "Stop playing";
16 | }
17 |
18 | @Override
19 | public String onPlay() {
20 | player.changeState(new ReadyState(player));
21 | return "Paused...";
22 | }
23 |
24 | @Override
25 | public String onNext() {
26 | return player.nextTrack();
27 | }
28 |
29 | @Override
30 | public String onPrevious() {
31 | return player.previousTrack();
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/states/ReadyState.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example.states;
2 |
3 | import refactoring_guru.state.example.ui.Player;
4 |
5 | /**
6 | * EN: They can also trigger state transitions in the context.
7 | *
8 | * RU: Они также могут переводить контекст в другие состояния.
9 | */
10 | public class ReadyState extends State {
11 |
12 | public ReadyState(Player player) {
13 | super(player);
14 | }
15 |
16 | @Override
17 | public String onLock() {
18 | player.changeState(new LockedState(player));
19 | return "Locked...";
20 | }
21 |
22 | @Override
23 | public String onPlay() {
24 | String action = player.startPlayback();
25 | player.changeState(new PlayingState(player));
26 | return action;
27 | }
28 |
29 | @Override
30 | public String onNext() {
31 | return "Locked...";
32 | }
33 |
34 | @Override
35 | public String onPrevious() {
36 | return "Locked...";
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/states/State.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example.states;
2 |
3 | import refactoring_guru.state.example.ui.Player;
4 |
5 | /**
6 | * EN: Common interface for all states.
7 | *
8 | * RU: Общий интерфейс всех состояний.
9 | */
10 | public abstract class State {
11 | Player player;
12 |
13 | /**
14 | * EN: Context passes itself through the state constructor. This may help a
15 | * state to fetch some useful context data if needed.
16 | *
17 | * RU: Контекст передаёт себя в конструктор состояния, чтобы состояние могло
18 | * обращаться к его данным и методам в будущем, если потребуется.
19 | */
20 | State(Player player) {
21 | this.player = player;
22 | }
23 |
24 | public abstract String onLock();
25 | public abstract String onPlay();
26 | public abstract String onNext();
27 | public abstract String onPrevious();
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/ui/Player.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example.ui;
2 |
3 | import refactoring_guru.state.example.states.ReadyState;
4 | import refactoring_guru.state.example.states.State;
5 |
6 | import java.util.ArrayList;
7 | import java.util.List;
8 |
9 | public class Player {
10 | private State state;
11 | private boolean playing = false;
12 | private List playlist = new ArrayList<>();
13 | private int currentTrack = 0;
14 |
15 | public Player() {
16 | this.state = new ReadyState(this);
17 | setPlaying(true);
18 | for (int i = 1; i <= 12; i++) {
19 | playlist.add("Track " + i);
20 | }
21 | }
22 |
23 | public void changeState(State state) {
24 | this.state = state;
25 | }
26 |
27 | public State getState() {
28 | return state;
29 | }
30 |
31 | public void setPlaying(boolean playing) {
32 | this.playing = playing;
33 | }
34 |
35 | public boolean isPlaying() {
36 | return playing;
37 | }
38 |
39 | public String startPlayback() {
40 | return "Playing " + playlist.get(currentTrack);
41 | }
42 |
43 | public String nextTrack() {
44 | currentTrack++;
45 | if (currentTrack > playlist.size() - 1) {
46 | currentTrack = 0;
47 | }
48 | return "Playing " + playlist.get(currentTrack);
49 | }
50 |
51 | public String previousTrack() {
52 | currentTrack--;
53 | if (currentTrack < 0) {
54 | currentTrack = playlist.size() - 1;
55 | }
56 | return "Playing " + playlist.get(currentTrack);
57 | }
58 |
59 | public void setCurrentTrackAfterStop() {
60 | this.currentTrack = 0;
61 | }
62 | }
63 |
--------------------------------------------------------------------------------
/src/refactoring_guru/state/example/ui/UI.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.state.example.ui;
2 |
3 | import javax.swing.*;
4 | import java.awt.*;
5 |
6 | public class UI {
7 | private Player player;
8 | private static JTextField textField = new JTextField();
9 |
10 | public UI(Player player) {
11 | this.player = player;
12 | }
13 |
14 | public void init() {
15 | JFrame frame = new JFrame("Test player");
16 | frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
17 | JPanel context = new JPanel();
18 | context.setLayout(new BoxLayout(context, BoxLayout.Y_AXIS));
19 | frame.getContentPane().add(context);
20 | JPanel buttons = new JPanel(new FlowLayout(FlowLayout.CENTER));
21 | context.add(textField);
22 | context.add(buttons);
23 |
24 | // EN: Context delegates handling user's input to a state object.
25 | // Naturally, the outcome will depend on what state is currently active,
26 | // since all states can handle the input differently.
27 | //
28 | // RU: Контекст заставляет состояние реагировать на пользовательский
29 | // ввод вместо себя. Реакция может быть разной в зависимости от того,
30 | // какое состояние сейчас активно.
31 | JButton play = new JButton("Play");
32 | play.addActionListener(e -> textField.setText(player.getState().onPlay()));
33 | JButton stop = new JButton("Stop");
34 | stop.addActionListener(e -> textField.setText(player.getState().onLock()));
35 | JButton next = new JButton("Next");
36 | next.addActionListener(e -> textField.setText(player.getState().onNext()));
37 | JButton prev = new JButton("Prev");
38 | prev.addActionListener(e -> textField.setText(player.getState().onPrevious()));
39 | frame.setVisible(true);
40 | frame.setSize(300, 100);
41 | buttons.add(play);
42 | buttons.add(stop);
43 | buttons.add(next);
44 | buttons.add(prev);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/refactoring_guru/strategy/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Please, select a product:
2 | 1 - Mother board
3 | 2 - CPU
4 | 3 - HDD
5 | 4 - Memory
6 | 1
7 | Count: 2
8 | Do you wish to continue selecting products? Y/N: y
9 | Please, select a product:
10 | 1 - Mother board
11 | 2 - CPU
12 | 3 - HDD
13 | 4 - Memory
14 | 2
15 | Count: 1
16 | Do you wish to continue selecting products? Y/N: n
17 | Please, select a payment method:
18 | 1 - PalPay
19 | 2 - Credit Card
20 | 1
21 | Enter the user's email: user@example.com
22 | Enter the password: qwerty
23 | Wrong email or password!
24 | Enter user email: amanda@ya.com
25 | Enter password: amanda1985
26 | Data verification has been successful.
27 | Pay 6250 units or Continue shopping? P/C: p
28 | Paying 6250 using PayPal.
29 | Payment has been successful.
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/strategy/example/order/Order.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.strategy.example.order;
2 |
3 | import refactoring_guru.strategy.example.strategies.PayStrategy;
4 |
5 | /**
6 | * EN: Order class. Doesn't know the concrete payment method (strategy) user has
7 | * picked. It uses common strategy interface to delegate collecting payment data
8 | * to strategy object. It can be used to save order to database.
9 | *
10 | * RU: Класс заказа. Ничего не знает о том каким способом (стратегией) будет
11 | * расчитыватся клиент, а просто вызывает метод оплаты. Все остальное стратегия
12 | * делает сама.
13 | */
14 | public class Order {
15 | private int totalCost = 0;
16 | private boolean isClosed = false;
17 |
18 | public void processOrder(PayStrategy strategy) {
19 | strategy.collectPaymentDetails();
20 | // EN: Here we could collect and store payment data from the strategy.
21 | //
22 | // RU: Здесь мы могли бы забрать и сохранить платежные данные из
23 | // стратегии.
24 | }
25 |
26 | public void setTotalCost(int cost) {
27 | this.totalCost += cost;
28 | }
29 |
30 | public int getTotalCost() {
31 | return totalCost;
32 | }
33 |
34 | public boolean isClosed() {
35 | return isClosed;
36 | }
37 |
38 | public void setClosed() {
39 | isClosed = true;
40 | }
41 | }
42 |
43 |
--------------------------------------------------------------------------------
/src/refactoring_guru/strategy/example/strategies/CreditCard.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.strategy.example.strategies;
2 |
3 | /**
4 | * EN: Dummy credit card class.
5 | *
6 | * RU: Очень наивная реализация кредитной карты.
7 | */
8 | public class CreditCard {
9 | private int amount;
10 | private String number;
11 | private String date;
12 | private String cvv;
13 |
14 | CreditCard(String number, String date, String cvv) {
15 | this.amount = 100_000;
16 | this.number = number;
17 | this.date = date;
18 | this.cvv = cvv;
19 | }
20 |
21 | public void setAmount(int amount) {
22 | this.amount = amount;
23 | }
24 |
25 | public int getAmount() {
26 | return amount;
27 | }
28 | }
29 |
30 |
--------------------------------------------------------------------------------
/src/refactoring_guru/strategy/example/strategies/PayByCreditCard.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.strategy.example.strategies;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 |
7 | /**
8 | * EN: Concrete strategy. Implements credit card payment method.
9 | *
10 | * RU: Конкретная стратегия. Реализует оплату корзины интернет магазина
11 | * кредитной картой клиента.
12 | */
13 | public class PayByCreditCard implements PayStrategy {
14 | private final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));
15 | private CreditCard card;
16 |
17 | /**
18 | * EN: Collect credit card data.
19 | *
20 | * RU: Собираем данные карты клиента.
21 | */
22 | @Override
23 | public void collectPaymentDetails() {
24 | try {
25 | System.out.print("Enter the card number: ");
26 | String number = READER.readLine();
27 | System.out.print("Enter the card expiration date 'mm/yy': ");
28 | String date = READER.readLine();
29 | System.out.print("Enter the CVV code: ");
30 | String cvv = READER.readLine();
31 | card = new CreditCard(number, date, cvv);
32 |
33 | // EN: Validate credit card number...
34 | //
35 | // RU: Валидируем номер карты...
36 |
37 | } catch (IOException ex) {
38 | ex.printStackTrace();
39 | }
40 | }
41 |
42 | /**
43 | * EN: After card validation we can charge customer's credit card.
44 | *
45 | * RU: После проверки карты мы можем совершить оплату. Если клиент
46 | * продолжает покупки, мы не запрашиваем карту заново.
47 | */
48 | @Override
49 | public boolean pay(int paymentAmount) {
50 | if (cardIsPresent()) {
51 | System.out.println("Paying " + paymentAmount + " using Credit Card.");
52 | card.setAmount(card.getAmount() - paymentAmount);
53 | return true;
54 | } else {
55 | return false;
56 | }
57 | }
58 |
59 | private boolean cardIsPresent() {
60 | return card != null;
61 | }
62 | }
63 |
64 |
--------------------------------------------------------------------------------
/src/refactoring_guru/strategy/example/strategies/PayByPayPal.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.strategy.example.strategies;
2 |
3 | import java.io.BufferedReader;
4 | import java.io.IOException;
5 | import java.io.InputStreamReader;
6 | import java.util.HashMap;
7 | import java.util.Map;
8 |
9 | /**
10 | * EN: Concrete strategy. Implements PayPal payment method.
11 | *
12 | * RU: Конкретная стратегия. Реализует оплату корзины интернет магазина через
13 | * платежную систему PayPal.
14 | */
15 | public class PayByPayPal implements PayStrategy {
16 | private static final Map DATA_BASE = new HashMap<>();
17 | private final BufferedReader READER = new BufferedReader(new InputStreamReader(System.in));
18 | private String email;
19 | private String password;
20 | private boolean signedIn;
21 |
22 | static {
23 | DATA_BASE.put("amanda1985", "amanda@ya.com");
24 | DATA_BASE.put("qwerty", "john@amazon.eu");
25 | }
26 |
27 | /**
28 | * EN: Collect customer's data.
29 | *
30 | * RU: Собираем данные от клиента.
31 | */
32 | @Override
33 | public void collectPaymentDetails() {
34 | try {
35 | while (!signedIn) {
36 | System.out.print("Enter the user's email: ");
37 | email = READER.readLine();
38 | System.out.print("Enter the password: ");
39 | password = READER.readLine();
40 | if (verify()) {
41 | System.out.println("Data verification has been successful.");
42 | } else {
43 | System.out.println("Wrong email or password!");
44 | }
45 | }
46 | } catch (IOException ex) {
47 | ex.printStackTrace();
48 | }
49 | }
50 |
51 | private boolean verify() {
52 | setSignedIn(email.equals(DATA_BASE.get(password)));
53 | return signedIn;
54 | }
55 |
56 | /**
57 | * EN: Save customer data for future shopping attempts.
58 | *
59 | * RU: Если клиент уже вошел в систему, то для следующей оплаты данные
60 | * вводить не придется.
61 | */
62 | @Override
63 | public boolean pay(int paymentAmount) {
64 | if (signedIn) {
65 | System.out.println("Paying " + paymentAmount + " using PayPal.");
66 | return true;
67 | } else {
68 | return false;
69 | }
70 | }
71 |
72 | private void setSignedIn(boolean signedIn) {
73 | this.signedIn = signedIn;
74 | }
75 | }
76 |
77 |
--------------------------------------------------------------------------------
/src/refactoring_guru/strategy/example/strategies/PayStrategy.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.strategy.example.strategies;
2 |
3 | /**
4 | * EN: Common interface for all strategies.
5 | *
6 | * RU: Общий интерфейс всех стратегий.
7 | */
8 | public interface PayStrategy {
9 | boolean pay(int paymentAmount);
10 | void collectPaymentDetails();
11 | }
12 |
13 |
--------------------------------------------------------------------------------
/src/refactoring_guru/template_method/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.template_method.example;
2 |
3 | import refactoring_guru.template_method.example.networks.Facebook;
4 | import refactoring_guru.template_method.example.networks.Network;
5 | import refactoring_guru.template_method.example.networks.Twitter;
6 |
7 | import java.io.BufferedReader;
8 | import java.io.IOException;
9 | import java.io.InputStreamReader;
10 |
11 | /**
12 | * EN: Demo class. Everything comes together here.
13 | *
14 | * RU: Демо-класс. Здесь всё сводится воедино.
15 | */
16 | public class Demo {
17 | public static void main(String[] args) throws IOException {
18 | BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
19 | Network network = null;
20 | System.out.print("Input user name: ");
21 | String userName = reader.readLine();
22 | System.out.print("Input password: ");
23 | String password = reader.readLine();
24 |
25 | // EN: Enter the message.
26 | //
27 | // RU: Вводим сообщение.
28 | System.out.print("Input message: ");
29 | String message = reader.readLine();
30 |
31 | System.out.println("\nChoose social network for posting message.\n" +
32 | "1 - Facebook\n" +
33 | "2 - Twitter");
34 | int choice = Integer.parseInt(reader.readLine());
35 |
36 | // EN: Create proper network object and send the message.
37 | //
38 | // RU: Создаем сетевые объекты и публикуем пост.
39 | if (choice == 1) {
40 | network = new Facebook(userName, password);
41 | } else if (choice == 2) {
42 | network = new Twitter(userName, password);
43 | }
44 | network.post(message);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/src/refactoring_guru/template_method/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 | Input user name: Jhonatan
2 | Input password: qswe
3 | Input message: Hello, World!
4 |
5 | Choose social network for posting message.
6 | 1 - Facebook
7 | 2 - Twitter
8 | 2
9 |
10 | Checking user's parameters
11 | Name: Jhonatan
12 | Password: ****
13 | ..........
14 |
15 | LogIn success on Twitter
16 | Message: 'Hello, World!' was posted on Twitter
17 | User: 'Jhonatan' was logged out from Twitter
--------------------------------------------------------------------------------
/src/refactoring_guru/template_method/example/networks/Facebook.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.template_method.example.networks;
2 |
3 | /**
4 | * EN: Class of social network
5 | *
6 | * RU: Класс социальной сети.
7 | */
8 | public class Facebook extends Network {
9 | public Facebook(String userName, String password) {
10 | this.userName = userName;
11 | this.password = password;
12 | }
13 |
14 | public boolean logIn(String userName, String password) {
15 | System.out.println("\nChecking user's parameters");
16 | System.out.println("Name: " + this.userName);
17 | System.out.print("Password: ");
18 | for (int i = 0; i < this.password.length(); i++) {
19 | System.out.print("*");
20 | }
21 | simulateNetworkLatency();
22 | System.out.println("\n\nLogIn success on Facebook");
23 | return true;
24 | }
25 |
26 | public boolean sendData(byte[] data) {
27 | boolean messagePosted = true;
28 | if (messagePosted) {
29 | System.out.println("Message: '" + new String(data) + "' was posted on Facebook");
30 | return true;
31 | } else {
32 | return false;
33 | }
34 | }
35 |
36 | public void logOut() {
37 | System.out.println("User: '" + userName + "' was logged out from Facebook");
38 | }
39 |
40 | private void simulateNetworkLatency() {
41 | try {
42 | int i = 0;
43 | System.out.println();
44 | while (i < 10) {
45 | System.out.print(".");
46 | Thread.sleep(500);
47 | i++;
48 | }
49 | } catch (InterruptedException ex) {
50 | ex.printStackTrace();
51 | }
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/src/refactoring_guru/template_method/example/networks/Network.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.template_method.example.networks;
2 |
3 | /**
4 | * EN: Base class of social network.
5 | *
6 | * RU: Базовый класс социальной сети.
7 | */
8 | public abstract class Network {
9 | String userName;
10 | String password;
11 |
12 | Network() {}
13 |
14 | /**
15 | * EN: Publish the data to whatever network.
16 | *
17 | * RU: Публикация данных в любой сети.
18 | */
19 | public boolean post(String message) {
20 | // EN: Authenticate before posting. Every network uses a different
21 | // authentication method.
22 | //
23 | // RU: Проверка данных пользователя перед постом в соцсеть. Каждая сеть
24 | // для проверки использует разные методы.
25 | if (logIn(this.userName, this.password)) {
26 | // EN: Send the post data.
27 | //
28 | // RU: Отправка данных.
29 | boolean result = sendData(message.getBytes());
30 | logOut();
31 | return result;
32 | }
33 | return false;
34 | }
35 |
36 | abstract boolean logIn(String userName, String password);
37 | abstract boolean sendData(byte[] data);
38 | abstract void logOut();
39 | }
--------------------------------------------------------------------------------
/src/refactoring_guru/template_method/example/networks/Twitter.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.template_method.example.networks;
2 |
3 | /**
4 | * EN: Class of social network
5 | *
6 | * RU: Класс социальной сети.
7 | */
8 | public class Twitter extends Network {
9 |
10 | public Twitter(String userName, String password) {
11 | this.userName = userName;
12 | this.password = password;
13 | }
14 |
15 | public boolean logIn(String userName, String password) {
16 | System.out.println("\nChecking user's parameters");
17 | System.out.println("Name: " + this.userName);
18 | System.out.print("Password: ");
19 | for (int i = 0; i < this.password.length(); i++) {
20 | System.out.print("*");
21 | }
22 | simulateNetworkLatency();
23 | System.out.println("\n\nLogIn success on Twitter");
24 | return true;
25 | }
26 |
27 | public boolean sendData(byte[] data) {
28 | boolean messagePosted = true;
29 | if (messagePosted) {
30 | System.out.println("Message: '" + new String(data) + "' was posted on Twitter");
31 | return true;
32 | } else {
33 | return false;
34 | }
35 | }
36 |
37 | public void logOut() {
38 | System.out.println("User: '" + userName + "' was logged out from Twitter");
39 | }
40 |
41 | private void simulateNetworkLatency() {
42 | try {
43 | int i = 0;
44 | System.out.println();
45 | while (i < 10) {
46 | System.out.print(".");
47 | Thread.sleep(500);
48 | i++;
49 | }
50 | } catch (InterruptedException ex) {
51 | ex.printStackTrace();
52 | }
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/Demo.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example;
2 |
3 | import refactoring_guru.visitor.example.shapes.*;
4 | import refactoring_guru.visitor.example.visitor.XMLExportVisitor;
5 |
6 | public class Demo {
7 | public static void main(String[] args) {
8 | Dot dot = new Dot(1, 10, 55);
9 | Circle circle = new Circle(2, 23, 15, 10);
10 | Rectangle rectangle = new Rectangle(3, 10, 17, 20, 30);
11 |
12 | CompoundShape compoundShape = new CompoundShape(4);
13 | compoundShape.add(dot);
14 | compoundShape.add(circle);
15 | compoundShape.add(rectangle);
16 |
17 | CompoundShape c = new CompoundShape(5);
18 | c.add(dot);
19 | compoundShape.add(c);
20 |
21 | export(circle, compoundShape);
22 | }
23 |
24 | private static void export(Shape... shapes) {
25 | XMLExportVisitor exportVisitor = new XMLExportVisitor();
26 | System.out.println(exportVisitor.export(shapes));
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/OutputDemo.txt:
--------------------------------------------------------------------------------
1 |
2 |
3 | 2
4 | 23
5 | 15
6 | 10
7 |
8 |
9 |
10 |
11 | 4
12 |
13 | 1
14 | 10
15 | 55
16 |
17 |
18 | 2
19 | 23
20 | 15
21 | 10
22 |
23 |
24 | 3
25 | 10
26 | 17
27 | 20
28 | 30
29 |
30 |
31 | 5
32 |
33 | 1
34 | 10
35 | 55
36 |
37 |
38 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/shapes/Circle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.shapes;
2 |
3 | import refactoring_guru.visitor.example.visitor.Visitor;
4 |
5 | public class Circle extends Dot {
6 | private int radius;
7 |
8 | public Circle(int id, int x, int y, int radius) {
9 | super(id, x, y);
10 | this.radius = radius;
11 | }
12 |
13 | @Override
14 | public String accept(Visitor visitor) {
15 | return visitor.visitCircle(this);
16 | }
17 |
18 | public int getRadius() {
19 | return radius;
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/shapes/CompoundShape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.shapes;
2 |
3 | import refactoring_guru.visitor.example.visitor.Visitor;
4 |
5 | import java.util.ArrayList;
6 | import java.util.List;
7 |
8 | public class CompoundShape implements Shape {
9 | public int id;
10 | public List children = new ArrayList<>();
11 |
12 | public CompoundShape(int id) {
13 | this.id = id;
14 | }
15 |
16 | @Override
17 | public void move(int x, int y) {
18 | // move shape
19 | }
20 |
21 | @Override
22 | public void draw() {
23 | // draw shape
24 | }
25 |
26 | public int getId() {
27 | return id;
28 | }
29 |
30 | @Override
31 | public String accept(Visitor visitor) {
32 | return visitor.visitCompoundGraphic(this);
33 | }
34 |
35 | public void add(Shape shape) {
36 | children.add(shape);
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/shapes/Dot.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.shapes;
2 |
3 | import refactoring_guru.visitor.example.visitor.Visitor;
4 |
5 | public class Dot implements Shape {
6 | private int id;
7 | private int x;
8 | private int y;
9 |
10 | public Dot() {
11 | }
12 |
13 | public Dot(int id, int x, int y) {
14 | this.id = id;
15 | this.x = x;
16 | this.y = y;
17 | }
18 |
19 | @Override
20 | public void move(int x, int y) {
21 | // move shape
22 | }
23 |
24 | @Override
25 | public void draw() {
26 | // draw shape
27 | }
28 |
29 | @Override
30 | public String accept(Visitor visitor) {
31 | return visitor.visitDot(this);
32 | }
33 |
34 | public int getX() {
35 | return x;
36 | }
37 |
38 | public int getY() {
39 | return y;
40 | }
41 |
42 | public int getId() {
43 | return id;
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/shapes/Rectangle.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.shapes;
2 |
3 | import refactoring_guru.visitor.example.visitor.Visitor;
4 |
5 | public class Rectangle implements Shape {
6 | private int id;
7 | private int x;
8 | private int y;
9 | private int width;
10 | private int height;
11 |
12 | public Rectangle(int id, int x, int y, int width, int height) {
13 | this.id = id;
14 | this.x = x;
15 | this.y = y;
16 | this.width = width;
17 | this.height = height;
18 | }
19 |
20 | @Override
21 | public String accept(Visitor visitor) {
22 | return visitor.visitRectangle(this);
23 | }
24 |
25 | @Override
26 | public void move(int x, int y) {
27 | // move shape
28 | }
29 |
30 | @Override
31 | public void draw() {
32 | // draw shape
33 | }
34 |
35 | public int getId() {
36 | return id;
37 | }
38 |
39 | public int getX() {
40 | return x;
41 | }
42 |
43 | public int getY() {
44 | return y;
45 | }
46 |
47 | public int getWidth() {
48 | return width;
49 | }
50 |
51 | public int getHeight() {
52 | return height;
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/shapes/Shape.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.shapes;
2 |
3 | import refactoring_guru.visitor.example.visitor.Visitor;
4 |
5 | public interface Shape {
6 | void move(int x, int y);
7 | void draw();
8 | String accept(Visitor visitor);
9 | }
10 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/visitor/Visitor.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.visitor;
2 |
3 | import refactoring_guru.visitor.example.shapes.Circle;
4 | import refactoring_guru.visitor.example.shapes.CompoundShape;
5 | import refactoring_guru.visitor.example.shapes.Dot;
6 | import refactoring_guru.visitor.example.shapes.Rectangle;
7 |
8 | public interface Visitor {
9 | String visitDot(Dot dot);
10 |
11 | String visitCircle(Circle circle);
12 |
13 | String visitRectangle(Rectangle rectangle);
14 |
15 | String visitCompoundGraphic(CompoundShape cg);
16 | }
17 |
--------------------------------------------------------------------------------
/src/refactoring_guru/visitor/example/visitor/XMLExportVisitor.java:
--------------------------------------------------------------------------------
1 | package refactoring_guru.visitor.example.visitor;
2 |
3 | import refactoring_guru.visitor.example.shapes.*;
4 |
5 | public class XMLExportVisitor implements Visitor {
6 |
7 | public String export(Shape... args) {
8 | StringBuilder sb = new StringBuilder();
9 | sb.append("" + "\n");
10 | for (Shape shape : args) {
11 | sb.append(shape.accept(this)).append("\n");
12 | }
13 | return sb.toString();
14 | }
15 |
16 | public String visitDot(Dot d) {
17 | return "" + "\n" +
18 | " " + d.getId() + "" + "\n" +
19 | " " + d.getX() + "" + "\n" +
20 | " " + d.getY() + "" + "\n" +
21 | "";
22 | }
23 |
24 | public String visitCircle(Circle c) {
25 | return "" + "\n" +
26 | " " + c.getId() + "" + "\n" +
27 | " " + c.getX() + "" + "\n" +
28 | " " + c.getY() + "" + "\n" +
29 | " " + c.getRadius() + "" + "\n" +
30 | "";
31 | }
32 |
33 | public String visitRectangle(Rectangle r) {
34 | return "" + "\n" +
35 | " " + r.getId() + "" + "\n" +
36 | " " + r.getX() + "" + "\n" +
37 | " " + r.getY() + "" + "\n" +
38 | " " + r.getWidth() + "" + "\n" +
39 | " " + r.getHeight() + "" + "\n" +
40 | "";
41 | }
42 |
43 | public String visitCompoundGraphic(CompoundShape cg) {
44 | return "" + "\n" +
45 | " " + cg.getId() + "" + "\n" +
46 | _visitCompoundGraphic(cg) +
47 | "";
48 | }
49 |
50 | private String _visitCompoundGraphic(CompoundShape cg) {
51 | StringBuilder sb = new StringBuilder();
52 | for (Shape shape : cg.children) {
53 | String obj = shape.accept(this);
54 | // Proper indentation for sub-objects.
55 | obj = " " + obj.replace("\n", "\n ") + "\n";
56 | sb.append(obj);
57 | }
58 | return sb.toString();
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------