├── .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 | Creative Commons License 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 | --------------------------------------------------------------------------------