{"id":2308,"date":"2026-07-20T12:41:36","date_gmt":"2026-07-20T10:41:36","guid":{"rendered":"https:\/\/kindsonthegenius.com\/blog\/the-software-design-patterns-behavioural-patterns-part-3\/"},"modified":"2026-08-27T17:45:23","modified_gmt":"2026-08-27T15:45:23","slug":"the-software-design-patterns-behavioural-patterns-part-3","status":"publish","type":"post","link":"https:\/\/kindsonthegenius.com\/blog\/the-software-design-patterns-behavioural-patterns-part-3\/","title":{"rendered":"The Software Design Patterns \u2013 Behavioural Patterns (Part 3)"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\"><em>Learn five essential behavioural design patterns in Java, including Strategy, Observer, Command, Template Method, and State, with practical examples and use cases.<\/em><\/p>\n\n\n<p><!-- ktg-updated-banner --><\/p>\n<p><em>Updated August 2026 \u2014 Behavioural Patterns (Part 3) restored for this URL.<\/em><\/p>\n<h2>TL;DR<\/h2>\n<ul>\n<li>\n<p><strong>Behavioural patterns<\/strong> define how objects communicate, share responsibilities, and manage workflows.<\/p>\n<\/li>\n<li>\n<p><strong>Strategy<\/strong> lets you swap algorithms at runtime without relying on long <code>if\/else<\/code> or <code>switch<\/code> chains.<\/p>\n<\/li>\n<li>\n<p><strong>Observer and Command<\/strong> support event-driven communication, queued actions, logging, and undoable operations.<\/p>\n<\/li>\n<li>\n<p><strong>Template Method and State<\/strong> organize fixed workflows and state-specific behavior without complex conditional logic.<\/p>\n<\/li>\n<li>\n<p><strong>Choose patterns based on the problem<\/strong>, not the pattern name. Use the smallest pattern that reduces coupling or removes unnecessary complexity.<\/p>\n<\/li>\n<\/ul>\n<p>This is <strong>Part 3<\/strong> of <em>Software Design Patterns<\/em>. We already covered:<\/p>\n<ul>\n<li><a href=\"https:\/\/kindsonthegenius.com\/blog\/the-software-design-patterns-creational-patterns-part-1\/\"><strong>Part 1<\/strong> \u2013 Creational Patterns<\/a><\/li>\n<li><a href=\"https:\/\/kindsonthegenius.com\/blog\/the-software-design-patterns-structural-patterns-part-2\/\"><strong>Part 2<\/strong> \u2013 Structural Patterns<\/a><\/li>\n<\/ul>\n<p><strong>Behavioural<\/strong> patterns describe how objects assign responsibilities and talk to each other \u2014 algorithms, notifications, undo stacks, and workflows.<\/p>\n<p>We will cover:<\/p>\n<ol>\n<li><a href=\"#t1\">Strategy Pattern<\/a><\/li>\n<li><a href=\"#t2\">Observer Pattern<\/a><\/li>\n<li><a href=\"#t3\">Command Pattern<\/a><\/li>\n<li><a href=\"#t4\">Template Method Pattern<\/a><\/li>\n<li><a href=\"#t5\">State Pattern<\/a><\/li>\n<\/ol>\n<p><strong id=\"t1\">1. Strategy Pattern<\/strong><\/p>\n<p><strong>Strategy<\/strong> lets you swap algorithms at runtime without rewriting the caller. Shipping cost, payment method, and sort comparators are common strategies.<\/p>\n<pre><code>interface ShippingStrategy {\n    int quoteCents(int weightGrams);\n}\n\nclass FlatRateShipping implements ShippingStrategy {\n    public int quoteCents(int weightGrams) { return 500; }\n}\n\nclass WeightShipping implements ShippingStrategy {\n    public int quoteCents(int weightGrams) { return weightGrams; } \/\/ 1 cent\/gram\n}\n\nclass Checkout {\n    private ShippingStrategy shipping;\n    Checkout(ShippingStrategy shipping) { this.shipping = shipping; }\n    void setShipping(ShippingStrategy s) { this.shipping = s; }\n    int total(int itemCents, int weightGrams) {\n        return itemCents + shipping.quoteCents(weightGrams);\n    }\n}\n\nCheckout cart = new Checkout(new FlatRateShipping());\nSystem.out.println(cart.total(2000, 800));\ncart.setShipping(new WeightShipping());\nSystem.out.println(cart.total(2000, 800));\n<\/code><\/pre>\n<p>Prefer Strategy over long <code>if\/else<\/code> or <code>switch<\/code> chains that pick an algorithm.<\/p>\n<p><strong id=\"t2\">2. Observer Pattern<\/strong><\/p>\n<p><strong>Observer<\/strong> (publish\/subscribe): when a subject changes, all registered observers are notified. UI listeners, event buses, and stock tickers use this idea.<\/p>\n<pre><code>interface Observer {\n    void update(String event);\n}\n\nclass OrderSubject {\n    private final List&lt;Observer&gt; observers = new ArrayList&lt;&gt;();\n    void subscribe(Observer o) { observers.add(o); }\n    void unsubscribe(Observer o) { observers.remove(o); }\n    void publish(String event) {\n        for (Observer o : observers) o.update(event);\n    }\n}\n\nclass EmailObserver implements Observer {\n    public void update(String event) {\n        System.out.println(\"Email got: \" + event);\n    }\n}\n\nclass AnalyticsObserver implements Observer {\n    public void update(String event) {\n        System.out.println(\"Analytics got: \" + event);\n    }\n}\n\nOrderSubject orders = new OrderSubject();\norders.subscribe(new EmailObserver());\norders.subscribe(new AnalyticsObserver());\norders.publish(\"ORDER_PAID\");\n<\/code><\/pre>\n<p>Keep observers lightweight. Heavy work should go to a queue so one slow listener does not block others.<\/p>\n<p><strong id=\"t3\">3. Command Pattern<\/strong><\/p>\n<p><strong>Command<\/strong> wraps a request as an object. You can queue it, log it, undo it, or send it across a network.<\/p>\n<pre><code>interface Command {\n    void execute();\n    void undo();\n}\n\nclass Light {\n    void on() { System.out.println(\"Light ON\"); }\n    void off() { System.out.println(\"Light OFF\"); }\n}\n\nclass LightOnCommand implements Command {\n    private final Light light;\n    LightOnCommand(Light light) { this.light = light; }\n    public void execute() { light.on(); }\n    public void undo() { light.off(); }\n}\n\nclass Remote {\n    private final Deque&lt;Command&gt; history = new ArrayDeque&lt;&gt;();\n    void press(Command cmd) {\n        cmd.execute();\n        history.push(cmd);\n    }\n    void undo() {\n        if (!history.isEmpty()) history.pop().undo();\n    }\n}\n\nLight lamp = new Light();\nRemote remote = new Remote();\nremote.press(new LightOnCommand(lamp));\nremote.undo();\n<\/code><\/pre>\n<p>Editors (undo\/redo) and job queues are textbook Command uses.<\/p>\n<p><strong id=\"t4\">4. Template Method Pattern<\/strong><\/p>\n<p><strong>Template Method<\/strong> defines the skeleton of an algorithm in a base class; subclasses fill in steps without changing the overall order.<\/p>\n<pre><code>abstract class DataImporter {\n    public final void run(String path) {\n        byte[] raw = read(path);\n        List&lt;String&gt; rows = parse(raw);\n        persist(rows);\n        afterImport();\n    }\n\n    protected abstract byte[] read(String path);\n    protected abstract List&lt;String&gt; parse(byte[] raw);\n    protected abstract void persist(List&lt;String&gt; rows);\n    protected void afterImport() { \/* optional hook *\/ }\n}\n\nclass CsvImporter extends DataImporter {\n    protected byte[] read(String path) { return path.getBytes(); }\n    protected List&lt;String&gt; parse(byte[] raw) {\n        return Arrays.asList(new String(raw).split(\"\\n\"));\n    }\n    protected void persist(List&lt;String&gt; rows) {\n        System.out.println(\"Saving \" + rows.size() + \" CSV rows\");\n    }\n}\n<\/code><\/pre>\n<p>The <code>final run<\/code> method locks the workflow; subclasses cannot reorder steps accidentally.<\/p>\n<p><strong id=\"t5\">5. State Pattern<\/strong><\/p>\n<p><strong>State<\/strong> lets an object alter behavior when its internal state changes \u2014 as if the class changed. Order lifecycles (<code>NEW<\/code> \u2192 <code>PAID<\/code> \u2192 <code>SHIPPED<\/code>) map well to State.<\/p>\n<pre><code>interface OrderState {\n    void pay(OrderContext ctx);\n    void ship(OrderContext ctx);\n}\n\nclass OrderContext {\n    private OrderState state = new NewState();\n    void setState(OrderState s) { this.state = s; }\n    void pay() { state.pay(this); }\n    void ship() { state.ship(this); }\n}\n\nclass NewState implements OrderState {\n    public void pay(OrderContext ctx) {\n        System.out.println(\"Payment accepted\");\n        ctx.setState(new PaidState());\n    }\n    public void ship(OrderContext ctx) {\n        throw new IllegalStateException(\"Pay first\");\n    }\n}\n\nclass PaidState implements OrderState {\n    public void pay(OrderContext ctx) {\n        throw new IllegalStateException(\"Already paid\");\n    }\n    public void ship(OrderContext ctx) {\n        System.out.println(\"Shipped\");\n        ctx.setState(new ShippedState());\n    }\n}\n\nclass ShippedState implements OrderState {\n    public void pay(OrderContext ctx) { \/* no-op or error *\/ }\n    public void ship(OrderContext ctx) { \/* already shipped *\/ }\n}\n<\/code><\/pre>\n<p>Compared with a giant <code>switch (status)<\/code>, State keeps each status\u2019s rules in its own class.<\/p>\n<p><strong>Wrap-up<\/strong><\/p>\n<ul>\n<li><strong>Creational<\/strong> \u2013 how objects are created (Part 1)<\/li>\n<li><strong>Structural<\/strong> \u2013 how objects are composed (Part 2)<\/li>\n<li><strong>Behavioural<\/strong> \u2013 how objects collaborate (this part)<\/li>\n<\/ul>\n<p>You do not need every pattern on every project. Learn to recognize the smell (long switches, fragile inheritance, tight coupling) and pick the smallest pattern that removes it.<\/p>\n<p>Start again from <a href=\"https:\/\/kindsonthegenius.com\/blog\/the-software-design-patterns-creational-patterns-part-1\/\">Part 1<\/a> if you want the full series in order.<\/p>\n<h2>Final Thoughts<\/h2>\n<p>Behavioural design patterns are about making interactions between objects clearer and easier to manage. Instead of allowing algorithms, events, workflows, or state rules to become tangled inside large classes, these patterns give each responsibility a more deliberate structure.<\/p>\n<p>The five patterns in this part address different problems: <strong>Strategy<\/strong> handles interchangeable algorithms, <strong>Observer<\/strong> manages notifications, <strong>Command<\/strong> turns actions into objects, <strong>Template Method<\/strong> controls a consistent workflow, and <strong>State<\/strong> separates behavior based on an object\u2019s current state.<\/p>\n<p>You do not need to use every pattern in every project. The real skill is recognizing when code has become difficult to extend or maintain, then choosing the simplest pattern that solves the problem.<\/p>","protected":false},"excerpt":{"rendered":"<p>Learn five essential behavioural design patterns in Java, including Strategy, Observer, Command, Template Method, and State, with practical examples and use cases.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"pagelayer_contact_templates":[],"_pagelayer_content":"","footnotes":""},"categories":[35],"tags":[],"class_list":["post-2308","post","type-post","status-publish","format-standard","hentry","category-algorithms"],"acf":[],"_links":{"self":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2308","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/comments?post=2308"}],"version-history":[{"count":4,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2308\/revisions"}],"predecessor-version":[{"id":2524,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/posts\/2308\/revisions\/2524"}],"wp:attachment":[{"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/media?parent=2308"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/categories?post=2308"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/kindsonthegenius.com\/blog\/wp-json\/wp\/v2\/tags?post=2308"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}