├── README.md ├── libs └── lombok-1.16.10.jar └── src └── com └── xpinjection └── patterns ├── adapter ├── ModernAdapterClient.java └── canonical │ ├── AdapterClient.java │ ├── CharCounterTask.java │ └── ExecutorConsumerAdaptor.java ├── builder ├── FutureBuilderClient.java ├── FutureCluster.java ├── LombokBuilderClient.java ├── LombokCluster.java └── canonical │ ├── BuilderClient.java │ └── Cluster.java ├── chain ├── ModernAuthRequestHandler.java ├── ModernChainClient.java └── canonical │ ├── AbstractRequestHandler.java │ ├── AuthRequestHandler.java │ ├── ChainClient.java │ ├── LoggingRequestHandler.java │ ├── Request.java │ └── RequestHandler.java ├── command ├── ModernCommandClient.java ├── ModernMacro.java └── canonical │ ├── BoldCommand.java │ ├── Command.java │ ├── CommandClient.java │ ├── Document.java │ ├── Editor.java │ ├── ItalicCommand.java │ ├── Macro.java │ └── UnderlineCommand.java ├── decorator ├── ModernDecoratorClient.java └── canonical │ ├── BenchmarkingDigitCounter.java │ ├── DecoratorClient.java │ ├── DigitCounter.java │ └── NaiveDigitCounter.java ├── factorymethod ├── ModernFactoryMethodClient.java └── canonical │ ├── Document.java │ ├── DocumentFactory.java │ ├── FactoryMethodClient.java │ ├── JsonDocument.java │ └── JsonDocumentFactory.java ├── iterator ├── ModernIteratorClient.java ├── ModernMultilineText.java ├── ModernText.java └── canonical │ ├── IteratorClient.java │ ├── LineIterator.java │ ├── MultilineText.java │ └── Text.java ├── observer ├── ModernObserver.java ├── ModernObserverClient.java ├── ModernTimeServer.java └── canonical │ ├── Event.java │ ├── EventListener.java │ ├── LoggingEventListener.java │ ├── Observer.java │ ├── ObserverClient.java │ └── TimeServer.java ├── prototype ├── Stats.java ├── StatsProcessor.java ├── TrafficStats.java └── canonical │ ├── Circle.java │ ├── Editor.java │ ├── Figure.java │ ├── PrototypeClient.java │ └── Rectangle.java ├── proxy ├── ModernProxyClient.java ├── PermissionChecker.java ├── canonical │ ├── Order.java │ ├── OrderService.java │ ├── PermissionCheckingOrderServiceProxy.java │ ├── ProxyClient.java │ └── RealOrderService.java └── spring-context.xml ├── singleton ├── ModernServiceRegistry.java ├── ModernSingletonClient.java ├── canonical │ ├── NamedService.java │ ├── ServiceRegistry.java │ └── SingletonClient.java └── spring-context.xml ├── strategy ├── ModernStrategyClient.java ├── TrafficCalculationStrategies.java └── canonical │ ├── PageTrafficCalculator.java │ ├── Position.java │ ├── StrategyClient.java │ ├── TopTrafficCalculator.java │ └── TrafficCalculator.java ├── templatemethod ├── LoggingUserStorage.java ├── ModernTemplateMethodClient.java ├── ModernUserRestorer.java └── canonical │ ├── AbstractUserRestorer.java │ ├── LoggingUserRestorer.java │ ├── TemplateMethodClient.java │ └── User.java └── visitor ├── LambdaVisitor.java ├── ModernVisitorClient.java └── canonical ├── AreaVisitor.java ├── Circle.java ├── Element.java ├── PerimeterVisitor.java ├── Rectangle.java ├── Square.java ├── Visitor.java └── VisitorClient.java /README.md: -------------------------------------------------------------------------------- 1 | # design-patterns 2 | Modern view on classic design patterns implementation in Java 3 | 4 | [blog article](http://javaday.org.ua/modern-view-of-design-patterns-in-java/) 5 | -------------------------------------------------------------------------------- /libs/lombok-1.16.10.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xpinjection/design-patterns/06ea3b3f3f790146120e377a5cf4e70db4489090/libs/lombok-1.16.10.jar -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/adapter/ModernAdapterClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.adapter; 2 | 3 | import com.xpinjection.patterns.adapter.canonical.CharCounterTask; 4 | 5 | import java.util.concurrent.ExecutorService; 6 | import java.util.concurrent.Executors; 7 | import java.util.concurrent.TimeUnit; 8 | import java.util.concurrent.atomic.AtomicInteger; 9 | import java.util.stream.Stream; 10 | 11 | /** 12 | * @author Alimenkou Mikalai 13 | */ 14 | public class ModernAdapterClient { 15 | public static void main(String[] args) throws InterruptedException { 16 | ExecutorService executor = Executors.newFixedThreadPool(3); 17 | 18 | AtomicInteger counter = new AtomicInteger(); 19 | Stream.of("af", "bdf", "c") 20 | .map(s -> new CharCounterTask(s, counter)) 21 | .forEach(executor::execute); 22 | 23 | executor.shutdown(); 24 | executor.awaitTermination(1, TimeUnit.SECONDS); 25 | System.out.println("Total count: " + counter.get()); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/adapter/canonical/AdapterClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.adapter.canonical; 2 | 3 | import java.util.concurrent.ExecutorService; 4 | import java.util.concurrent.Executors; 5 | import java.util.concurrent.TimeUnit; 6 | import java.util.concurrent.atomic.AtomicInteger; 7 | import java.util.stream.Stream; 8 | 9 | /** 10 | * @author Alimenkou Mikalai 11 | */ 12 | public class AdapterClient { 13 | public static void main(String[] args) throws InterruptedException { 14 | ExecutorService executor = Executors.newFixedThreadPool(3); 15 | 16 | AtomicInteger counter = new AtomicInteger(); 17 | Stream.of("af", "bdf", "c") 18 | .map(s -> new CharCounterTask(s, counter)) 19 | .forEach(new ExecutorConsumerAdaptor(executor)); 20 | 21 | executor.shutdown(); 22 | executor.awaitTermination(1, TimeUnit.SECONDS); 23 | System.out.println("Total count: " + counter.get()); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/adapter/canonical/CharCounterTask.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.adapter.canonical; 2 | 3 | import java.util.concurrent.atomic.AtomicInteger; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | * @version 1.0 8 | */ 9 | public class CharCounterTask implements Runnable { 10 | private final String str; 11 | private final AtomicInteger counter; 12 | 13 | public CharCounterTask(String str, AtomicInteger counter) { 14 | this.str = str; 15 | this.counter = counter; 16 | } 17 | 18 | @Override 19 | public void run() { 20 | counter.addAndGet(str.length()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/adapter/canonical/ExecutorConsumerAdaptor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.adapter.canonical; 2 | 3 | import java.util.concurrent.Executor; 4 | import java.util.function.Consumer; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class ExecutorConsumerAdaptor implements Consumer { 10 | private final Executor executor; 11 | 12 | public ExecutorConsumerAdaptor(Executor executor) { 13 | this.executor = executor; 14 | } 15 | 16 | @Override 17 | public void accept(Runnable task) { 18 | executor.execute(task); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/builder/FutureBuilderClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.builder; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class FutureBuilderClient { 7 | /** With hope for better Java ;) 8 | * 9 | * public static void main(String[] args) { 10 | * FutureCluster cluster = new FutureCluster("localhost").setPort(3165) 11 | * .setRetryAttempts(3).setMetricsEnabled(false); 12 | * } 13 | */ 14 | } 15 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/builder/FutureCluster.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.builder; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class FutureCluster { 7 | /** With hope for better Java ;) 8 | * 9 | * property String[] hosts; 10 | * property int port; 11 | * property int retryAttempts; 12 | * property boolean metricsEnabled; 13 | * 14 | */ 15 | } 16 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/builder/LombokBuilderClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.builder; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class LombokBuilderClient { 7 | public static void main(String[] args) { 8 | LombokCluster cluster = LombokCluster.builder() 9 | .host("localhost").port(3165) 10 | .retryAttempts(3).metricsEnabled(false).build(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/builder/LombokCluster.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.builder; 2 | 3 | import lombok.Builder; 4 | import lombok.Getter; 5 | import lombok.Singular; 6 | 7 | import java.util.List; 8 | 9 | /** 10 | * @author Alimenkou Mikalai 11 | */ 12 | @Builder 13 | @Getter 14 | public class LombokCluster { 15 | @Singular private List hosts; 16 | private int port; 17 | private int retryAttempts; 18 | private boolean metricsEnabled; 19 | } 20 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/builder/canonical/BuilderClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.builder.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class BuilderClient { 7 | public static void main(String[] args) { 8 | Cluster cluster = Cluster.runtimeBuilder() 9 | .addContactPoints("localhost").withPort(3165) 10 | .withRetryAttempts(3) 11 | .withoutMetrics().build(); 12 | 13 | cluster = Cluster.storingBuilder() 14 | .addContactPoints("localhost").withPort(3165) 15 | .withRetryAttempts(3) 16 | .withoutMetrics().build(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/builder/canonical/Cluster.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.builder.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Cluster { 7 | private String[] hosts; 8 | private int port; 9 | private int retryAttempts; 10 | private boolean metricsEnabled; 11 | 12 | public static StoringBuilder storingBuilder() { 13 | return new StoringBuilder(); 14 | } 15 | 16 | public static RuntimeBuilder runtimeBuilder() { 17 | return new RuntimeBuilder(); 18 | } 19 | 20 | public Cluster(String[] hosts, int port) { 21 | this.hosts = hosts; 22 | this.port = port; 23 | } 24 | 25 | public Cluster() { 26 | } 27 | 28 | public void setHosts(String... hosts) { 29 | this.hosts = hosts; 30 | } 31 | 32 | public String[] getHosts() { 33 | return hosts; 34 | } 35 | 36 | public void setPort(int port) { 37 | this.port = port; 38 | } 39 | 40 | public int getPort() { 41 | return port; 42 | } 43 | 44 | public void setRetryAttempts(int retryAttempts) { 45 | this.retryAttempts = retryAttempts; 46 | } 47 | 48 | public int getRetryAttempts() { 49 | return retryAttempts; 50 | } 51 | 52 | public void setMetricsEnabled(boolean metricsEnabled) { 53 | this.metricsEnabled = metricsEnabled; 54 | } 55 | 56 | public boolean isMetricsEnabled() { 57 | return metricsEnabled; 58 | } 59 | 60 | public static class RuntimeBuilder { 61 | private Cluster cluster = new Cluster(); 62 | 63 | public RuntimeBuilder addContactPoints(String... hosts) { 64 | if (hosts == null || hosts.length == 0) { 65 | throw new IllegalArgumentException("Hosts must be set!"); 66 | } 67 | cluster.setHosts(hosts); 68 | return this; 69 | } 70 | 71 | public RuntimeBuilder withPort(int port) { 72 | cluster.setPort(port); 73 | return this; 74 | } 75 | 76 | public RuntimeBuilder withRetryAttempts(int retryAttempts) { 77 | cluster.setRetryAttempts(retryAttempts); 78 | return this; 79 | } 80 | 81 | public RuntimeBuilder withoutMetrics() { 82 | cluster.setMetricsEnabled(false); 83 | return this; 84 | } 85 | 86 | public Cluster build() { 87 | return cluster; 88 | } 89 | } 90 | 91 | public static class StoringBuilder { 92 | private String[] hosts; 93 | private int port; 94 | private int retryAttempts; 95 | private boolean metricsEnabled; 96 | 97 | public StoringBuilder addContactPoints(String... hosts) { 98 | if (hosts == null || hosts.length == 0) { 99 | throw new IllegalArgumentException("Hosts must be set!"); 100 | } 101 | this.hosts = hosts; 102 | return this; 103 | } 104 | 105 | public StoringBuilder withPort(int port) { 106 | this.port = port; 107 | return this; 108 | } 109 | 110 | public StoringBuilder withRetryAttempts(int retryAttempts) { 111 | this.retryAttempts = retryAttempts; 112 | return this; 113 | } 114 | 115 | public StoringBuilder withoutMetrics() { 116 | this.metricsEnabled = false; 117 | return this; 118 | } 119 | 120 | public Cluster build() { 121 | Cluster cluster = new Cluster(hosts, port); 122 | cluster.setMetricsEnabled(metricsEnabled); 123 | cluster.setRetryAttempts(retryAttempts); 124 | return cluster; 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/ModernAuthRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain; 2 | 3 | import com.xpinjection.patterns.chain.canonical.Request; 4 | 5 | import java.util.function.Consumer; 6 | 7 | /** 8 | * @author Alimenkou Mikalai 9 | */ 10 | public class ModernAuthRequestHandler implements Consumer { 11 | private static final ThreadLocal currentUser = new ThreadLocal<>(); 12 | 13 | @Override 14 | public void accept(Request request) { 15 | currentUser.set(request.getUserId()); 16 | System.out.println("Current user is set to: " + request.getUserId()); 17 | request.addParam("AUTH_PASSED", "TRUE"); 18 | } 19 | 20 | public static Long getCurrentUser() { 21 | return currentUser.get(); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/ModernChainClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain; 2 | 3 | import com.xpinjection.patterns.chain.canonical.Request; 4 | 5 | import java.util.function.Consumer; 6 | import java.util.stream.Stream; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class ModernChainClient { 12 | public static void main(String[] args) { 13 | Request request = new Request(5); 14 | chain(new ModernAuthRequestHandler(), ModernChainClient::log) 15 | .accept(request); 16 | } 17 | 18 | @SafeVarargs 19 | public static Consumer chain(Consumer... handlers) { 20 | return Stream.of(handlers) 21 | .reduce(Consumer::andThen) 22 | .get(); 23 | } 24 | 25 | private static void log(Request request) { 26 | System.out.println("Request arrived: " + request); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/canonical/AbstractRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public abstract class AbstractRequestHandler implements RequestHandler { 7 | private final RequestHandler next; 8 | 9 | public AbstractRequestHandler(RequestHandler next) { 10 | this.next = next; 11 | } 12 | 13 | protected void passToTheNext(Request request) { 14 | if (next != null) { 15 | next.handleRequest(request); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/canonical/AuthRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class AuthRequestHandler extends AbstractRequestHandler { 7 | private static final ThreadLocal currentUser = new ThreadLocal<>(); 8 | 9 | public AuthRequestHandler(RequestHandler next) { 10 | super(next); 11 | } 12 | 13 | @Override 14 | public void handleRequest(Request request) { 15 | currentUser.set(request.getUserId()); 16 | System.out.println("Current user is set to: " + request.getUserId()); 17 | request.addParam("AUTH_PASSED", "TRUE"); 18 | passToTheNext(request); 19 | } 20 | 21 | public static Long getCurrentUser() { 22 | return currentUser.get(); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/canonical/ChainClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class ChainClient { 7 | public static void main(String[] args) { 8 | Request request = new Request(5); 9 | RequestHandler handler = new AuthRequestHandler(new LoggingRequestHandler(null)); 10 | handler.handleRequest(request); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/canonical/LoggingRequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class LoggingRequestHandler extends AbstractRequestHandler { 7 | public LoggingRequestHandler(RequestHandler next) { 8 | super(next); 9 | } 10 | 11 | @Override 12 | public void handleRequest(Request request) { 13 | System.out.println("Request arrived: " + request); 14 | passToTheNext(request); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/canonical/Request.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain.canonical; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class Request { 10 | private final long userId; 11 | private final Map params = new HashMap<>(); 12 | 13 | public Request(long userId) { 14 | this.userId = userId; 15 | } 16 | 17 | public Request addParam(String name, String value) { 18 | params.put(name, value); 19 | return this; 20 | } 21 | 22 | public long getUserId() { 23 | return userId; 24 | } 25 | 26 | public Map getParams() { 27 | return params; 28 | } 29 | 30 | @Override 31 | public String toString() { 32 | return "Request{userId=" + userId + ", params=" + params + "}"; 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/chain/canonical/RequestHandler.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.chain.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface RequestHandler { 7 | void handleRequest(Request request); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/ModernCommandClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command; 2 | 3 | import com.xpinjection.patterns.command.canonical.Document; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class ModernCommandClient { 9 | public static void main(String[] args) { 10 | Document editor = new Document(); 11 | ModernMacro macro = new ModernMacro(); 12 | 13 | macro.record(editor::bold) 14 | .record(editor::italic) 15 | .record(editor::underline) 16 | .run(); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/ModernMacro.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command; 2 | 3 | import com.xpinjection.patterns.command.canonical.Command; 4 | 5 | import java.util.ArrayList; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class ModernMacro { 12 | private final List commands = new ArrayList<>(); 13 | 14 | public ModernMacro record(Command action) { 15 | commands.add(action); 16 | return this; 17 | } 18 | 19 | public void run() { 20 | commands.forEach(Command::execute); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/BoldCommand.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class BoldCommand implements Command { 7 | private final Editor editor; 8 | 9 | public BoldCommand(Editor editor) { 10 | this.editor = editor; 11 | } 12 | 13 | @Override 14 | public void execute() { 15 | editor.bold(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/Command.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Command { 7 | void execute(); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/CommandClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class CommandClient { 7 | public static void main(String[] args) { 8 | Document editor = new Document(); 9 | 10 | Macro macro = new Macro(); 11 | macro.record(new BoldCommand(editor)); 12 | macro.record(new ItalicCommand(editor)); 13 | macro.record(new UnderlineCommand(editor)); 14 | macro.run(); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/Document.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Document implements Editor { 7 | @Override 8 | public void bold() { 9 | System.out.println("Bold text..."); 10 | } 11 | 12 | @Override 13 | public void italic() { 14 | System.out.println("Italic text..."); 15 | } 16 | 17 | @Override 18 | public void underline() { 19 | System.out.println("Underline text..."); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/Editor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Editor { 7 | void bold(); 8 | 9 | void italic(); 10 | 11 | void underline(); 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/ItalicCommand.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class ItalicCommand implements Command { 7 | private final Editor editor; 8 | 9 | public ItalicCommand(Editor editor) { 10 | this.editor = editor; 11 | } 12 | 13 | @Override 14 | public void execute() { 15 | editor.italic(); 16 | } 17 | } 18 | 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/Macro.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class Macro { 10 | private final List commands = new ArrayList<>(); 11 | 12 | public void record(Command action) { 13 | commands.add(action); 14 | } 15 | 16 | public void run() { 17 | for (Command command : commands) { 18 | command.execute(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/command/canonical/UnderlineCommand.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.command.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class UnderlineCommand implements Command { 7 | private final Editor editor; 8 | 9 | public UnderlineCommand(Editor editor) { 10 | this.editor = editor; 11 | } 12 | 13 | @Override 14 | public void execute() { 15 | editor.underline(); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/decorator/ModernDecoratorClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.decorator; 2 | 3 | import com.xpinjection.patterns.decorator.canonical.DigitCounter; 4 | import com.xpinjection.patterns.decorator.canonical.NaiveDigitCounter; 5 | 6 | import java.util.function.Function; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class ModernDecoratorClient { 12 | public static void main(String[] args) { 13 | DigitCounter counter = wrap(new NaiveDigitCounter()); 14 | int digitsCount = counter.count("fd6j78fh19kj"); 15 | System.out.println(digitsCount + " digits found"); 16 | 17 | digitsCount = ((Function) String::trim) 18 | .andThen(new NaiveDigitCounter()::count) 19 | .apply(" \n 123 \t"); 20 | System.out.println(digitsCount + " digits found"); 21 | } 22 | 23 | public static DigitCounter wrap(DigitCounter counter) { 24 | return s -> { 25 | long startTime = System.currentTimeMillis(); 26 | int count = counter.count(s); 27 | long endTime = System.currentTimeMillis(); 28 | System.out.println("Counting took " + (endTime - startTime) + " ms"); 29 | return count; 30 | }; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/decorator/canonical/BenchmarkingDigitCounter.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.decorator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class BenchmarkingDigitCounter implements DigitCounter { 7 | private final DigitCounter delegate; 8 | 9 | public BenchmarkingDigitCounter(DigitCounter delegate) { 10 | this.delegate = delegate; 11 | } 12 | 13 | @Override 14 | public int count(String str) { 15 | long startTime = System.currentTimeMillis(); 16 | int count = delegate.count(str); 17 | long endTime = System.currentTimeMillis(); 18 | System.out.println("Counting took " + (endTime - startTime) + " ms"); 19 | return count; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/decorator/canonical/DecoratorClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.decorator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class DecoratorClient { 7 | public static void main(String[] args) { 8 | DigitCounter counter = new BenchmarkingDigitCounter(new NaiveDigitCounter()); 9 | int digitsCount = counter.count("fd6j78fh19kj"); 10 | System.out.println(digitsCount + " digits found"); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/decorator/canonical/DigitCounter.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.decorator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface DigitCounter { 7 | int count(String str); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/decorator/canonical/NaiveDigitCounter.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.decorator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class NaiveDigitCounter implements DigitCounter { 7 | @Override 8 | public int count(String str) { 9 | int count = 0; 10 | for (int i = 0; i < str.length(); i++) { 11 | char c = str.charAt(i); 12 | if (Character.isDigit(c)) { 13 | count++; 14 | } 15 | } 16 | return count; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/factorymethod/ModernFactoryMethodClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.factorymethod; 2 | 3 | import com.xpinjection.patterns.factorymethod.canonical.Document; 4 | import com.xpinjection.patterns.factorymethod.canonical.DocumentFactory; 5 | import com.xpinjection.patterns.factorymethod.canonical.JsonDocument; 6 | 7 | import java.util.function.Function; 8 | 9 | /** 10 | * @author Alimenkou Mikalai 11 | */ 12 | public class ModernFactoryMethodClient { 13 | public static void main(String[] args) { 14 | DocumentFactory factory = JsonDocument::new; 15 | printUserDetails(factory.create("USER")); 16 | 17 | Function plainFactory = JsonDocument::new; 18 | printUserDetails(plainFactory.apply("USER")); 19 | } 20 | 21 | private static void printUserDetails(Document document) { 22 | document.addField("name", "Mikalai"); 23 | document.addField("surname", "Alimenkou"); 24 | System.out.println(document); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/factorymethod/canonical/Document.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.factorymethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Document { 7 | String getName(); 8 | 9 | void addField(String name, String value); 10 | 11 | String toString(); 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/factorymethod/canonical/DocumentFactory.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.factorymethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface DocumentFactory { 7 | Document create(String name); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/factorymethod/canonical/FactoryMethodClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.factorymethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class FactoryMethodClient { 7 | public static void main(String[] args) { 8 | DocumentFactory factory = new JsonDocumentFactory(); 9 | Document document = factory.create("USER"); 10 | document.addField("name", "Mikalai"); 11 | document.addField("surname", "Alimenkou"); 12 | System.out.println(document); 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/factorymethod/canonical/JsonDocument.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.factorymethod.canonical; 2 | 3 | import java.util.LinkedHashMap; 4 | import java.util.Map; 5 | import java.util.stream.Collectors; 6 | 7 | /** 8 | * @author Alimenkou Mikalai 9 | */ 10 | public class JsonDocument implements Document { 11 | private final String name; 12 | private final Map fields = new LinkedHashMap<>(); 13 | 14 | public JsonDocument(String name) { 15 | this.name = name; 16 | } 17 | 18 | @Override 19 | public String getName() { 20 | return name; 21 | } 22 | 23 | @Override 24 | public void addField(String name, String value) { 25 | fields.put(name, value); 26 | } 27 | 28 | @Override 29 | public String toString() { 30 | return fields.entrySet().stream() 31 | .map(e -> e.getKey() + ": " + e.getValue()) 32 | .collect(Collectors.joining(",\n", "{\n", "\n}")); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/factorymethod/canonical/JsonDocumentFactory.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.factorymethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class JsonDocumentFactory implements DocumentFactory { 7 | @Override 8 | public Document create(String name) { 9 | return new JsonDocument(name); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/ModernIteratorClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator; 2 | 3 | import java.util.Arrays; 4 | import java.util.stream.Collectors; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class ModernIteratorClient { 10 | public static void main(String[] args) { 11 | ModernText text = new ModernMultilineText("This is just \n" + 12 | " a simple multiline \n" + 13 | "\n" + 14 | " text\n" + 15 | "\n", "\n"); 16 | text.linesStream().forEach(System.out::println); 17 | 18 | String sentence = "JEEConf is the oldest Java conference in Ukraine"; 19 | System.out.println(capitalize(sentence)); 20 | } 21 | 22 | private static String capitalize(String sentence) { 23 | return Arrays.stream(sentence.split(" ")) 24 | .filter(word -> word.length() > 4) 25 | .map(String::toUpperCase) 26 | .collect(Collectors.joining(" ")); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/ModernMultilineText.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator; 2 | 3 | import java.util.Spliterator; 4 | import java.util.Spliterators; 5 | import java.util.function.Consumer; 6 | import java.util.stream.Stream; 7 | import java.util.stream.StreamSupport; 8 | 9 | /** 10 | * @author Alimenkou Mikalai 11 | */ 12 | public class ModernMultilineText implements ModernText { 13 | private final String text; 14 | private final String lineSeparator; 15 | 16 | public ModernMultilineText(String text, String lineSeparator) { 17 | this.text = text; 18 | this.lineSeparator = lineSeparator; 19 | } 20 | 21 | @Override 22 | public Stream linesStream() { 23 | return StreamSupport.stream(new LineSupplier(), false); 24 | } 25 | 26 | private class LineSupplier extends Spliterators.AbstractSpliterator { 27 | private int lineStartIndex = 0; 28 | 29 | public LineSupplier() { 30 | super(Long.MAX_VALUE, Spliterator.NONNULL | Spliterator.SIZED); 31 | } 32 | 33 | @Override 34 | public boolean tryAdvance(Consumer action) { 35 | if (lineStartIndex >= text.length()) { 36 | return false; 37 | } 38 | int separatorIndex = text.indexOf(lineSeparator, lineStartIndex + 1); 39 | if (separatorIndex < 0) { 40 | separatorIndex = text.length() - 1; 41 | } 42 | String line = text.substring(lineStartIndex, separatorIndex); 43 | action.accept(line); 44 | lineStartIndex = separatorIndex + 1; 45 | return true; 46 | } 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/ModernText.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator; 2 | 3 | import java.util.stream.Stream; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public interface ModernText { 9 | Stream linesStream(); 10 | } 11 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/canonical/IteratorClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class IteratorClient { 7 | public static void main(String[] args) { 8 | Text text = new MultilineText("This is just \n" + 9 | " a simple multiline \n" + 10 | "\n" + 11 | " text\n" + 12 | "\n", "\n"); 13 | LineIterator lineIterator = text.lineIterator(); 14 | String line = lineIterator.nextLine(); 15 | while (line != null) { 16 | System.out.println(line); 17 | line = lineIterator.nextLine(); 18 | } 19 | 20 | String sentence = "JEEConf is the oldest Java conference in Ukraine"; 21 | System.out.println(capitalize(sentence)); 22 | } 23 | 24 | private static String capitalize(String sentence) { 25 | String[] words = sentence.split(" "); 26 | StringBuilder caps = new StringBuilder(); 27 | 28 | for (String word : words) { 29 | if (word.length() > 4) { 30 | caps.append(word.toUpperCase()).append(' '); 31 | } 32 | } 33 | 34 | return caps.toString().trim(); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/canonical/LineIterator.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface LineIterator { 7 | String nextLine(); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/canonical/MultilineText.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class MultilineText implements Text { 7 | private final String text; 8 | private final String lineSeparator; 9 | 10 | public MultilineText(String text, String lineSeparator) { 11 | this.text = text; 12 | this.lineSeparator = lineSeparator; 13 | } 14 | 15 | @Override 16 | public LineIterator lineIterator() { 17 | return new SeparatorBasedLineIterator(); 18 | } 19 | 20 | private class SeparatorBasedLineIterator implements LineIterator { 21 | private int lineStartIndex = 0; 22 | 23 | @Override 24 | public String nextLine() { 25 | if (lineStartIndex >= text.length()) { 26 | return null; 27 | } 28 | int separatorIndex = text.indexOf(lineSeparator, lineStartIndex + 1); 29 | if (separatorIndex < 0) { 30 | separatorIndex = text.length() - 1; 31 | } 32 | String line = text.substring(lineStartIndex, separatorIndex); 33 | lineStartIndex = separatorIndex + 1; 34 | return line; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/iterator/canonical/Text.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.iterator.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Text { 7 | LineIterator lineIterator(); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/ModernObserver.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer; 2 | 3 | import com.xpinjection.patterns.observer.canonical.Event; 4 | 5 | import java.util.function.Consumer; 6 | 7 | /** 8 | * @author Alimenkou Mikalai 9 | */ 10 | public interface ModernObserver { 11 | void addListener(Consumer listener); 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/ModernObserverClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer; 2 | 3 | import com.xpinjection.patterns.observer.canonical.Event; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class ModernObserverClient { 9 | public static void main(String[] args) { 10 | ModernTimeServer server = new ModernTimeServer(); 11 | server.addListener(ModernObserverClient::log); 12 | server.addListener(e -> System.out.println("ANOTHER EVENT: " + e.getName())); 13 | server.reportTime(); 14 | server.reportTime(); 15 | } 16 | 17 | public static void log(Event event) { 18 | System.out.println("EVENT: " + event.getName()); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/ModernTimeServer.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer; 2 | 3 | import com.xpinjection.patterns.observer.canonical.Event; 4 | 5 | import java.text.SimpleDateFormat; 6 | import java.util.Date; 7 | import java.util.Queue; 8 | import java.util.concurrent.ConcurrentLinkedQueue; 9 | import java.util.function.Consumer; 10 | 11 | /** 12 | * @author Alimenkou Mikalai 13 | */ 14 | public class ModernTimeServer implements ModernObserver { 15 | private static final String TIME_FORMAT = "HH:mm:ss"; 16 | 17 | private final Queue> listeners = new ConcurrentLinkedQueue<>(); 18 | 19 | @Override 20 | public void addListener(Consumer listener) { 21 | listeners.add(listener); 22 | } 23 | 24 | public void reportTime() { 25 | Event event = new Event(new SimpleDateFormat(TIME_FORMAT).format(new Date())); 26 | listeners.forEach(listener -> listener.accept(event)); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/canonical/Event.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Event { 7 | private final String name; 8 | 9 | public Event(String name) { 10 | this.name = name; 11 | } 12 | 13 | public String getName() { 14 | return name; 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/canonical/EventListener.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface EventListener { 7 | void onEvent(Event event); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/canonical/LoggingEventListener.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class LoggingEventListener implements EventListener { 7 | @Override 8 | public void onEvent(Event event) { 9 | System.out.println("EVENT: " + event.getName()); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/canonical/Observer.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Observer { 7 | void addListener(EventListener listener); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/canonical/ObserverClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class ObserverClient { 7 | public static void main(String[] args) { 8 | TimeServer server = new TimeServer(); 9 | server.addListener(new LoggingEventListener()); 10 | server.reportTime(); 11 | server.reportTime(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/observer/canonical/TimeServer.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.observer.canonical; 2 | 3 | import java.text.SimpleDateFormat; 4 | import java.util.ArrayList; 5 | import java.util.Date; 6 | import java.util.List; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class TimeServer implements Observer { 12 | private static final String TIME_FORMAT = "HH:mm:ss"; 13 | 14 | private final List listeners = new ArrayList<>(); 15 | 16 | @Override 17 | public void addListener(EventListener listener) { 18 | listeners.add(listener); 19 | } 20 | 21 | public void reportTime() { 22 | Event event = new Event(new SimpleDateFormat(TIME_FORMAT).format(new Date())); 23 | for (EventListener listener : listeners) { 24 | listener.onEvent(event); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/Stats.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public interface Stats { 9 | S add(S delta); 10 | 11 | S invert(Date forDate); 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/StatsProcessor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype; 2 | 3 | import java.util.Date; 4 | import java.util.List; 5 | import java.util.stream.Collectors; 6 | 7 | /** 8 | * @author Alimenkou Mikalai 9 | */ 10 | public class StatsProcessor { 11 | public List process(long domainId, List stats) { 12 | Date now = new Date(); 13 | return stats.stream() 14 | .filter(stat -> stat.getDomainId() == domainId) 15 | .map(stat -> stat.invert(now)) 16 | .collect(Collectors.toList()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/TrafficStats.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype; 2 | 3 | import java.util.Date; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class TrafficStats implements Stats { 9 | private final long domainId; 10 | private final Date rankDate; 11 | 12 | private long estimatedTraffic; 13 | 14 | public TrafficStats(long domainId, Date rankDate) { 15 | this.domainId = domainId; 16 | this.rankDate = rankDate; 17 | } 18 | 19 | private TrafficStats(long domainId, Date rankDate, long traffic) { 20 | this(domainId, rankDate); 21 | this.estimatedTraffic = traffic; 22 | } 23 | 24 | public long getDomainId() { 25 | return domainId; 26 | } 27 | 28 | public Date getRankDate() { 29 | return rankDate; 30 | } 31 | 32 | public void setEstimatedTraffic(long estimatedTraffic) { 33 | this.estimatedTraffic = estimatedTraffic; 34 | } 35 | 36 | public long getEstimatedTraffic() { 37 | return estimatedTraffic; 38 | } 39 | 40 | @Override 41 | public TrafficStats add(TrafficStats delta) { 42 | return new TrafficStats(domainId, rankDate, estimatedTraffic + delta.estimatedTraffic); 43 | } 44 | 45 | @Override 46 | public TrafficStats invert(Date forDate) { 47 | return new TrafficStats(domainId, forDate, -estimatedTraffic); 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "TrafficStats{domainId=" + domainId + ", rankDate=" + rankDate + 53 | ", estimatedTraffic=" + estimatedTraffic + "}"; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/canonical/Circle.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Circle implements Figure { 7 | private int radix; 8 | 9 | public Circle(int radix) { 10 | this.radix = radix; 11 | } 12 | 13 | public void changeRadix(int delta) { 14 | radix += delta; 15 | } 16 | 17 | @Override 18 | public double getSquare() { 19 | return Math.PI * radix * radix; 20 | } 21 | 22 | @Override 23 | public Circle clone() { 24 | return new Circle(radix); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/canonical/Editor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype.canonical; 2 | 3 | import java.util.ArrayList; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class Editor { 10 | private final List
figures = new ArrayList<>(); 11 | 12 | private final Circle defaultCircle = new Circle(5); 13 | private final Rectangle defaultRectangle = new Rectangle(2, 4); 14 | 15 | public Circle addCircle() { 16 | Circle circle = defaultCircle.clone(); 17 | figures.add(circle); 18 | return circle; 19 | } 20 | 21 | public Rectangle addRectangle() { 22 | Rectangle rectangle = defaultRectangle.clone(); 23 | figures.add(rectangle); 24 | return rectangle; 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/canonical/Figure.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Figure { 7 | double getSquare(); 8 | 9 | Figure clone(); 10 | } 11 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/canonical/PrototypeClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class PrototypeClient { 7 | public static void main(String[] args) { 8 | Editor editor = new Editor(); 9 | 10 | Circle circle = editor.addCircle(); 11 | circle.changeRadix(5); 12 | 13 | Rectangle rectangle = editor.addRectangle(); 14 | rectangle.changeSize(1, -1); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/prototype/canonical/Rectangle.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.prototype.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Rectangle implements Figure { 7 | private int width; 8 | private int height; 9 | 10 | public Rectangle(int width, int height) { 11 | this.width = width; 12 | this.height = height; 13 | } 14 | 15 | public void changeSize(int widthDelta, int heightDelta) { 16 | width += widthDelta; 17 | height += heightDelta; 18 | } 19 | 20 | @Override 21 | public double getSquare() { 22 | return width * height; 23 | } 24 | 25 | @Override 26 | public Rectangle clone() { 27 | return new Rectangle(width, height); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/ModernProxyClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy; 2 | 3 | import com.xpinjection.patterns.proxy.canonical.Order; 4 | import com.xpinjection.patterns.proxy.canonical.RealOrderService; 5 | 6 | import java.util.function.Consumer; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class ModernProxyClient { 12 | public static void main(String[] args) { 13 | Order order = new Order(5L); 14 | order.putItem("XP", 2); 15 | 16 | RealOrderService service = new RealOrderService(); 17 | PermissionChecker checker = new PermissionChecker(); 18 | Consumer processing = ((Consumer) checker::checkPermission) 19 | .andThen(service::processOrder); 20 | 21 | checker.setCurrentUser(5); 22 | processing.accept(order); 23 | checker.setCurrentUser(2); 24 | processing.accept(order); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/PermissionChecker.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy; 2 | 3 | import com.xpinjection.patterns.proxy.canonical.Order; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class PermissionChecker { 9 | private final ThreadLocal currentUser = new ThreadLocal<>(); 10 | 11 | public void setCurrentUser(long userId) { 12 | currentUser.set(userId); 13 | } 14 | 15 | public void checkPermission(Order order) { 16 | if (order.getUserId() != currentUser.get()) { 17 | throw new IllegalStateException("Order for another user can't be processed: " + order); 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/canonical/Order.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy.canonical; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class Order { 10 | private final long userId; 11 | private final Map items = new HashMap<>(); 12 | 13 | public Order(long userId) { 14 | this.userId = userId; 15 | } 16 | 17 | public void putItem(String code, int count) { 18 | items.put(code, count); 19 | } 20 | 21 | public long getUserId() { 22 | return userId; 23 | } 24 | 25 | public Map getItems() { 26 | return items; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "Order{userId=" + userId + ", items=" + items + "}"; 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/canonical/OrderService.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface OrderService { 7 | void processOrder(Order order); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/canonical/PermissionCheckingOrderServiceProxy.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class PermissionCheckingOrderServiceProxy implements OrderService { 7 | private final ThreadLocal currentUser = new ThreadLocal<>(); 8 | private final OrderService delegate; 9 | 10 | public PermissionCheckingOrderServiceProxy(OrderService delegate) { 11 | this.delegate = delegate; 12 | } 13 | 14 | public void setCurrentUser(long userId) { 15 | currentUser.set(userId); 16 | } 17 | 18 | @Override 19 | public void processOrder(Order order) { 20 | if (order.getUserId() != currentUser.get()) { 21 | throw new IllegalStateException("Order for another user can't be processed: " + order); 22 | } 23 | delegate.processOrder(order); 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/canonical/ProxyClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class ProxyClient { 7 | public static void main(String[] args) { 8 | Order order = new Order(5L); 9 | order.putItem("XP", 2); 10 | 11 | RealOrderService service = new RealOrderService(); 12 | service.processOrder(order); 13 | 14 | PermissionCheckingOrderServiceProxy proxy = new PermissionCheckingOrderServiceProxy(service); 15 | proxy.setCurrentUser(5); 16 | proxy.processOrder(order); 17 | proxy.setCurrentUser(2); 18 | proxy.processOrder(order); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/canonical/RealOrderService.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.proxy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class RealOrderService implements OrderService { 7 | @Override 8 | public void processOrder(Order order) { 9 | System.out.println("Order processed: " + order); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/proxy/spring-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/singleton/ModernServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.singleton; 2 | 3 | import com.xpinjection.patterns.singleton.canonical.NamedService; 4 | 5 | import java.util.concurrent.ConcurrentHashMap; 6 | import java.util.concurrent.ConcurrentMap; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class ModernServiceRegistry { 12 | private final ConcurrentMap services = new ConcurrentHashMap<>(); 13 | 14 | public void register(NamedService service) { 15 | String name = service.getName(); 16 | System.out.println("Register service with name: " + name); 17 | services.put(name, service); 18 | } 19 | 20 | public NamedService getService(String name) { 21 | return services.get(name); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/singleton/ModernSingletonClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.singleton; 2 | 3 | import com.xpinjection.patterns.singleton.canonical.NamedService; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class ModernSingletonClient implements NamedService { 9 | private final ModernServiceRegistry registry; 10 | 11 | public ModernSingletonClient(ModernServiceRegistry registry) { 12 | this.registry = registry; 13 | } 14 | 15 | public static void main(String[] args) { 16 | ModernServiceRegistry registry = new ModernServiceRegistry(); 17 | new ModernSingletonClient(registry).start(); 18 | } 19 | 20 | public void start() { 21 | registry.register(this); 22 | } 23 | 24 | @Override 25 | public String getName() { 26 | return "MAIN"; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/singleton/canonical/NamedService.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.singleton.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface NamedService { 7 | String getName(); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/singleton/canonical/ServiceRegistry.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.singleton.canonical; 2 | 3 | import java.util.concurrent.ConcurrentHashMap; 4 | import java.util.concurrent.ConcurrentMap; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public final class ServiceRegistry { 10 | private static final ServiceRegistry INSTANCE = new ServiceRegistry(); 11 | 12 | public static ServiceRegistry getInstance() { 13 | return INSTANCE; 14 | } 15 | 16 | private final ConcurrentMap services = new ConcurrentHashMap<>(); 17 | 18 | private ServiceRegistry() {} 19 | 20 | public void register(NamedService service) { 21 | String name = service.getName(); 22 | System.out.println("Register service with name: " + name); 23 | services.put(name, service); 24 | } 25 | 26 | public NamedService getService(String name) { 27 | return services.get(name); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/singleton/canonical/SingletonClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.singleton.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class SingletonClient implements NamedService { 7 | public static void main(String[] args) { 8 | new SingletonClient().start(); 9 | } 10 | 11 | public void start() { 12 | ServiceRegistry.getInstance().register(this); 13 | } 14 | 15 | @Override 16 | public String getName() { 17 | return "MAIN"; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/singleton/spring-context.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/ModernStrategyClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy; 2 | 3 | import com.xpinjection.patterns.strategy.canonical.Position; 4 | 5 | import java.util.function.ToIntFunction; 6 | 7 | /** 8 | * @author Alimenkou Mikalai 9 | */ 10 | public class ModernStrategyClient { 11 | private final ToIntFunction calculator; 12 | 13 | public ModernStrategyClient(ToIntFunction calculator) { 14 | this.calculator = calculator; 15 | } 16 | 17 | public static void main(String[] args) { 18 | Position position = new Position(3, 1000); 19 | new ModernStrategyClient(TrafficCalculationStrategies::calculateTopTrafficOnly).process(position); 20 | new ModernStrategyClient(TrafficCalculationStrategies::calculateTrafficForPage).process(position); 21 | 22 | // for unit tests 23 | new ModernStrategyClient(pos -> 15).process(position); 24 | } 25 | 26 | public void process(Position position) { 27 | int traffic = calculator.applyAsInt(position); 28 | System.out.println("Traffic is " + traffic + " for position " + position); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/TrafficCalculationStrategies.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy; 2 | 3 | import com.xpinjection.patterns.strategy.canonical.Position; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public final class TrafficCalculationStrategies { 9 | private static final int PAGE_SIZE = 10; 10 | private static final double[] TOP_RANKS = {0.5, 0.3, 0.1, 0.05, 0.05}; 11 | 12 | private TrafficCalculationStrategies() {} 13 | 14 | public static int calculateTrafficForPage(Position position) { 15 | int rank = position.getRank(); 16 | if (rank < 0) { 17 | return 0; 18 | } 19 | int page = rank / PAGE_SIZE; 20 | return position.getMediaValue() / (PAGE_SIZE * (page + 1)); 21 | } 22 | 23 | public static int calculateTopTrafficOnly(Position position) { 24 | int rank = position.getRank(); 25 | if (rank < 0 || rank >= TOP_RANKS.length) { 26 | return 0; 27 | } 28 | return (int) (TOP_RANKS[rank] * position.getMediaValue()); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/canonical/PageTrafficCalculator.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class PageTrafficCalculator implements TrafficCalculator { 7 | private static final int PAGE_SIZE = 10; 8 | 9 | @Override 10 | public int calculate(Position position) { 11 | int rank = position.getRank(); 12 | if (rank < 0) { 13 | return 0; 14 | } 15 | int page = rank / PAGE_SIZE; 16 | return position.getMediaValue() / (PAGE_SIZE * (page + 1)); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/canonical/Position.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Position { 7 | private int rank; 8 | private int mediaValue; 9 | 10 | public Position(int rank, int mediaValue) { 11 | this.rank = rank; 12 | this.mediaValue = mediaValue; 13 | } 14 | 15 | public int getRank() { 16 | return rank; 17 | } 18 | 19 | public void setRank(int rank) { 20 | this.rank = rank; 21 | } 22 | 23 | public int getMediaValue() { 24 | return mediaValue; 25 | } 26 | 27 | public void setMediaValue(int mediaValue) { 28 | this.mediaValue = mediaValue; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return "Position{rank=" + rank + ", mediaValue=" + mediaValue + "}"; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/canonical/StrategyClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class StrategyClient { 7 | private final TrafficCalculator calculator; 8 | 9 | public StrategyClient(TrafficCalculator calculator) { 10 | this.calculator = calculator; 11 | } 12 | 13 | public static void main(String[] args) { 14 | Position position = new Position(3, 1000); 15 | new StrategyClient(new TopTrafficCalculator()).process(position); 16 | new StrategyClient(new PageTrafficCalculator()).process(position); 17 | } 18 | 19 | public void process(Position position) { 20 | int traffic = calculator.calculate(position); 21 | System.out.println("Traffic is " + traffic + " for position " + position); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/canonical/TopTrafficCalculator.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class TopTrafficCalculator implements TrafficCalculator { 7 | private static final double[] TOP_RANKS = {0.5, 0.3, 0.1, 0.05, 0.05}; 8 | 9 | @Override 10 | public int calculate(Position position) { 11 | int rank = position.getRank(); 12 | if (rank < 0 || rank >= TOP_RANKS.length) { 13 | return 0; 14 | } 15 | return (int) (TOP_RANKS[rank] * position.getMediaValue()); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/strategy/canonical/TrafficCalculator.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.strategy.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface TrafficCalculator { 7 | int calculate(Position position); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/LoggingUserStorage.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod; 2 | 3 | import com.xpinjection.patterns.templatemethod.canonical.User; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class LoggingUserStorage { 9 | public long store(User user) { 10 | System.out.println("User is stored: " + user); 11 | return System.currentTimeMillis(); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/ModernTemplateMethodClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod; 2 | 3 | import com.xpinjection.patterns.templatemethod.canonical.User; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public class ModernTemplateMethodClient { 9 | public static void main(String[] args) { 10 | LoggingUserStorage storage = new LoggingUserStorage(); 11 | User mikalai = new ModernUserRestorer(storage::store).restore("Mikalai:32"); 12 | System.out.println("Mikalai is restored: " + mikalai); 13 | 14 | // for unit tests 15 | mikalai = new ModernUserRestorer(user -> 5L).restore("Mikalai:32"); 16 | System.out.println("Mikalai is restored: " + mikalai); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/ModernUserRestorer.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod; 2 | 3 | import com.xpinjection.patterns.templatemethod.canonical.User; 4 | 5 | import java.util.StringTokenizer; 6 | import java.util.function.ToLongFunction; 7 | 8 | /** 9 | * @author Alimenkou Mikalai 10 | */ 11 | public class ModernUserRestorer { 12 | private static final String DELIMITER = ":"; 13 | 14 | private final ToLongFunction storage; 15 | 16 | public ModernUserRestorer(ToLongFunction storage) { 17 | this.storage = storage; 18 | } 19 | 20 | public User restore(String serialized) { 21 | StringTokenizer tokenizer = new StringTokenizer(serialized, DELIMITER); 22 | validate(tokenizer); 23 | User user = parse(tokenizer); 24 | long id = storage.applyAsLong(user); 25 | user.setId(id); 26 | return user; 27 | } 28 | 29 | private User parse(StringTokenizer tokenizer) { 30 | String name = tokenizer.nextToken(); 31 | int age = Integer.parseInt(tokenizer.nextToken()); 32 | return new User(name, age); 33 | } 34 | 35 | private void validate(StringTokenizer tokenizer) { 36 | if (tokenizer.countTokens() != 2) { 37 | throw new IllegalArgumentException("Invalid data format!"); 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/canonical/AbstractUserRestorer.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod.canonical; 2 | 3 | import java.util.StringTokenizer; 4 | 5 | /** 6 | * @author Alimenkou Mikalai 7 | */ 8 | public abstract class AbstractUserRestorer { 9 | private static final String DELIMITER = ":"; 10 | 11 | public final User restore(String serialized) { 12 | StringTokenizer tokenizer = new StringTokenizer(serialized, DELIMITER); 13 | validate(tokenizer); 14 | User user = parse(tokenizer); 15 | long id = store(user); 16 | user.setId(id); 17 | return user; 18 | } 19 | 20 | private User parse(StringTokenizer tokenizer) { 21 | String name = tokenizer.nextToken(); 22 | int age = Integer.parseInt(tokenizer.nextToken()); 23 | return new User(name, age); 24 | } 25 | 26 | private void validate(StringTokenizer tokenizer) { 27 | if (tokenizer.countTokens() != 2) { 28 | throw new IllegalArgumentException("Invalid data format!"); 29 | } 30 | } 31 | 32 | protected abstract long store(User user); 33 | } 34 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/canonical/LoggingUserRestorer.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class LoggingUserRestorer extends AbstractUserRestorer { 7 | @Override 8 | protected long store(User user) { 9 | System.out.println("User is stored: " + user); 10 | return System.currentTimeMillis(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/canonical/TemplateMethodClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class TemplateMethodClient { 7 | public static void main(String[] args) { 8 | User mikalai = new LoggingUserRestorer().restore("Mikalai:32"); 9 | System.out.println("Mikalai is restored: " + mikalai); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/templatemethod/canonical/User.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.templatemethod.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class User { 7 | private Long id; 8 | private String name; 9 | private int age; 10 | 11 | public User(String name, int age) { 12 | this.name = name; 13 | this.age = age; 14 | } 15 | 16 | public Long getId() { 17 | return id; 18 | } 19 | 20 | public void setId(Long id) { 21 | this.id = id; 22 | } 23 | 24 | public String getName() { 25 | return name; 26 | } 27 | 28 | public void setName(String name) { 29 | this.name = name; 30 | } 31 | 32 | public int getAge() { 33 | return age; 34 | } 35 | 36 | public void setAge(int age) { 37 | this.age = age; 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return "User{id=" + id + ", name='" + name + "', age=" + age + "}"; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/LambdaVisitor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | import java.util.function.Function; 6 | 7 | /** 8 | * @author Alimenkou Mikalai 9 | */ 10 | public class LambdaVisitor implements Function { 11 | private final Map, Function> functions = new HashMap<>(); 12 | 13 | public Acceptor on(Class clazz) { 14 | return new Acceptor<>(this, clazz); 15 | } 16 | 17 | @Override 18 | public A apply(Object o) { 19 | return functions.get(o.getClass()).apply(o); 20 | } 21 | 22 | public static class Acceptor { 23 | private final LambdaVisitor visitor; 24 | private final Class clazz; 25 | 26 | public Acceptor(LambdaVisitor visitor, Class clazz) { 27 | this.visitor = visitor; 28 | this.clazz = clazz; 29 | } 30 | 31 | public LambdaVisitor then(Function f) { 32 | visitor.functions.put(clazz, f); 33 | return visitor; 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/ModernVisitorClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor; 2 | 3 | import com.xpinjection.patterns.visitor.canonical.Circle; 4 | import com.xpinjection.patterns.visitor.canonical.Rectangle; 5 | import com.xpinjection.patterns.visitor.canonical.Square; 6 | 7 | import java.util.Arrays; 8 | import java.util.List; 9 | import java.util.function.Function; 10 | 11 | /** 12 | * @author Alimenkou Mikalai 13 | */ 14 | public class ModernVisitorClient { 15 | private final static Function AREA_CALCULATOR = new LambdaVisitor() 16 | .on(Square.class).then(s -> s.getSide() * s.getSide()) 17 | .on(Circle.class).then(c -> Math.PI * c.getRadius() * c.getRadius()) 18 | .on(Rectangle.class).then(r -> r.getHeight() * r.getWidth()); 19 | 20 | private final static Function PERIMETER_CALCULATOR = new LambdaVisitor() 21 | .on(Square.class).then(s -> 4 * s.getSide()) 22 | .on(Circle.class).then(c -> 2 * Math.PI * c.getRadius()) 23 | .on(Rectangle.class).then(r -> 2 * r.getHeight() + 2 * r.getWidth()); 24 | 25 | public static void main(String[] args) { 26 | List figures = Arrays.asList(new Circle(4), new Square(5), new Rectangle(6, 7)); 27 | 28 | double totalArea = figures.stream() 29 | .map(AREA_CALCULATOR) 30 | .reduce(0.0, Double::sum); 31 | System.out.println("Total area = " + totalArea); 32 | 33 | double totalPerimeter = figures.stream() 34 | .map(PERIMETER_CALCULATOR) 35 | .reduce(0.0, Double::sum); 36 | System.out.println("Total perimeter = " + totalPerimeter); 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/AreaVisitor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class AreaVisitor implements Visitor { 7 | @Override 8 | public Double visit(Square element) { 9 | return element.getSide() * element.getSide(); 10 | } 11 | 12 | @Override 13 | public Double visit(Circle element) { 14 | return Math.PI * element.getRadius() * element.getRadius(); 15 | } 16 | 17 | @Override 18 | public Double visit(Rectangle element) { 19 | return element.getHeight() * element.getWidth(); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/Circle.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Circle implements Element { 7 | private final double radius; 8 | 9 | public Circle(double radius) { 10 | this.radius = radius; 11 | } 12 | 13 | public double getRadius() { 14 | return radius; 15 | } 16 | 17 | @Override 18 | public T accept(Visitor visitor) { 19 | return visitor.visit(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/Element.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Element { 7 | T accept(Visitor visitor); 8 | } 9 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/PerimeterVisitor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class PerimeterVisitor implements Visitor { 7 | @Override 8 | public Double visit(Square element) { 9 | return 4 * element.getSide(); 10 | } 11 | 12 | @Override 13 | public Double visit(Circle element) { 14 | return 2 * Math.PI * element.getRadius(); 15 | } 16 | 17 | @Override 18 | public Double visit(Rectangle element) { 19 | return (2 * element.getHeight() + 2 * element.getWidth()); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/Rectangle.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Rectangle implements Element { 7 | private final double width; 8 | private final double height; 9 | 10 | public Rectangle(double width, double height) { 11 | this.width = width; 12 | this.height = height; 13 | } 14 | 15 | public double getWidth() { 16 | return width; 17 | } 18 | 19 | public double getHeight() { 20 | return height; 21 | } 22 | 23 | @Override 24 | public T accept(Visitor visitor) { 25 | return visitor.visit(this); 26 | } 27 | } -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/Square.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public class Square implements Element { 7 | private final double side; 8 | 9 | public Square(double side) { 10 | this.side = side; 11 | } 12 | 13 | public double getSide() { 14 | return side; 15 | } 16 | 17 | @Override 18 | public T accept(Visitor visitor) { 19 | return visitor.visit(this); 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/Visitor.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | /** 4 | * @author Alimenkou Mikalai 5 | */ 6 | public interface Visitor { 7 | T visit(Square element); 8 | 9 | T visit(Circle element); 10 | 11 | T visit(Rectangle element); 12 | } 13 | -------------------------------------------------------------------------------- /src/com/xpinjection/patterns/visitor/canonical/VisitorClient.java: -------------------------------------------------------------------------------- 1 | package com.xpinjection.patterns.visitor.canonical; 2 | 3 | import java.util.Arrays; 4 | import java.util.List; 5 | 6 | /** 7 | * @author Alimenkou Mikalai 8 | */ 9 | public class VisitorClient { 10 | public static void main(String[] args) { 11 | List figures = Arrays.asList(new Circle(4), new Square(5), new Rectangle(6, 7)); 12 | 13 | double totalArea = 0.0; 14 | Visitor areaVisitor = new AreaVisitor(); 15 | for (Element figure : figures) { 16 | totalArea += figure.accept(areaVisitor); 17 | } 18 | System.out.println("Total area = " + totalArea); 19 | 20 | double totalPerimeter = 0.0; 21 | Visitor perimeterVisitor = new PerimeterVisitor(); 22 | for (Element figure : figures) { 23 | totalPerimeter += figure.accept(perimeterVisitor); 24 | } 25 | System.out.println("Total perimeter = " + totalPerimeter); 26 | } 27 | } 28 | --------------------------------------------------------------------------------