DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports
Events Video Library
Refcards
Trend Reports

Events

View Events Video Library

Zones

Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks

Generative AI has transformed nearly every industry. How can you leverage GenAI to improve your productivity and efficiency?

SBOMs are essential to circumventing software supply chain attacks, and they provide visibility into various software components.

Related

  • Beyond Java Streams: Exploring Alternative Functional Programming Approaches in Java
  • Redefining Java Object Equality
  • Java vs. Scala: Comparative Analysis for Backend Development in Fintech
  • Singleton: 6 Ways To Write and Use in Java Programming

Trending

  • Testing the MongoDB MCP Server Using SingleStore Kai
  • Scaling Multi-Tenant Go Apps: Choosing the Right Database Partitioning Approach
  • When MySQL, PostgreSQL, and Oracle Argue: Doris JDBC Catalog Acts as the Peacemaker
  • Simplifying Code Migration: The Benefits of the New Ampere Porting Advisor for x86 to Arm64
  1. DZone
  2. Coding
  3. Java
  4. Kung Fu Code: Master Shifu Teaches Strategy Pattern to Po – The Functional Way

Kung Fu Code: Master Shifu Teaches Strategy Pattern to Po – The Functional Way

Master Shifu guides Po from bloated Java classes to cleaner functional code using the Strategy Pattern—showing that good code is about how you write it.

By 
Shaamik Mitraa user avatar
Shaamik Mitraa
·
Jun. 09, 25 · Tutorial
Likes (5)
Comment
Save
Tweet
Share
2.1K Views

Join the DZone community and get the full member experience.

Join For Free

"There is no good or bad code. But how you write it… that makes all the difference.” - Master Shifu

The sun had just touched the tips of the Valley of Peace. Birds chirped, the wind whispered tales of warriors, and Po—the Dragon Warrior—was busy trying to write some Java code. Yes, you read that right.

Master Shifu stood behind him, watching, amused and concerned.

Po (scratching his head): “Master Shifu, I’m trying to make this app where each Kung Fu move is chosen based on the enemy. But the code is… bloated. Classes everywhere. If OOP was noodles, this is a full buffet.”

Shifu (calmly sipping tea): “Ah, the classic Strategy Pattern. But there’s a better way, Po… a functional way. Let me show you the path.”

The Traditional (OOP) Strategy Pattern – Heavy Like Po’s Lunch   

Po wants to choose a fighting strategy based on his opponent.

Java
 
// Strategy Interface
interface FightStrategy {
    void fight();
}

// Concrete Strategies
class TigerFightStrategy implements FightStrategy {
    public void fight() {
        System.out.println("Attack with swift tiger strikes!");
    }
}

class MonkeyFightStrategy implements FightStrategy {
    public void fight() {
        System.out.println("Use agile monkey flips!");
    }
}

// Context
class Warrior {
    private FightStrategy strategy;

    public Warrior(FightStrategy strategy) {
        this.strategy = strategy;
    }

    public void fight() {
        strategy.fight();
    }

    public void setStrategy(FightStrategy strategy) {
        this.strategy = strategy;
    }
}

Usage

Java
 
Warrior po = new Warrior(new TigerFightStrategy());
po.fight();  // Output: Attack with swift tiger strikes!

po.setStrategy(new MonkeyFightStrategy());
po.fight();  // Output: Use agile monkey flips!

Why This Is a Problem (and Why Po Is Annoyed)

Po: “So many files, interfaces, boilerplate! All I want is to change moves easily. This feels like trying to meditate with a noodle cart passing by!”

Indeed, OOP Strategy pattern works, but it's verbose, rigid, and unnecessarily class-heavy. It violates the spirit of quick Kung Fu adaptability!

Enter Functional Programming – The Way of Inner Simplicity

Shifu (nodding): “Po, what if I told you… that functions themselves can be passed around like scrolls of wisdom?”  

Po: “Whoa... like… JScrolls? 

Shifu: “No, Po. Java lambdas.” 

In functional programming, functions are first-class citizens. You don’t need classes to wrap behavior. You can pass behavior directly.

Higher-Order Functions are functions that take other functions as parameters or return them.

Po, In Java 8 onwards, we can do that easily with the help of lambda. Lambda can wrap the functionality and can be passed to another method as a parameter.

Strategy Pattern – The Functional Way in Java

Java
 
import java.util.function.Consumer;

class Warrior {
    private Consumer<Void> strategy;

    public Warrior(Consumer<Void> strategy) {
        this.strategy = strategy;
    }

    public void fight() {
        strategy.accept(null);
    }

    public void setStrategy(Consumer<Void> strategy) {
        this.strategy = strategy;
    }
}


But there’s a better, cleaner way with just lambdas and no class at all. 

Java
 
import java.util.function.Supplier;

public class FunctionalStrategy {

    public static void main(String[] args) {
        // Each strategy is just a lambda
        Runnable tigerStyle = () -> System.out.println("Attack with swift tiger strikes!");
        Runnable monkeyStyle = () -> System.out.println("Use agile monkey flips!");
        Runnable pandaStyle = () -> System.out.println("Roll and belly-bounce!");

        // Fighter is a high-order function executor
        executeStrategy(tigerStyle);
        executeStrategy(monkeyStyle);
        executeStrategy(pandaStyle);
    }

    static void executeStrategy(Runnable strategy) {
        strategy.run();
    }
}


Shifu (with a gentle tone):

“Po, in the art of code—as in Kung Fu—not every move needs a name, nor every master a title. In our example, we summoned the ancient scroll of Runnable… a humble interface with but one method—run(). In Java 8, we call it Functional Interface.

Think of it as a silent warrior—it expects no inputs (parameters), demands no rewards (return type), and yet, performs its duty when called.

Each fighting style—tiger, monkey, panda—was not wrapped in robes of classes, but flowed freely as lambdas.

And then, we had the executeStrategy() method… a higher-order sensei.

It does not fight itself, Po. It simply receives the wisdom of a move—a function—and executes it when the time is right.

This… is the way of functional composition.

You do not command the move—you invite it.

You do not create many paths—you simply choose the next step.”

Benefits – As Clear As The Sacred Pool of Tears

  • No extra interfaces or classes
  •  Easily switch behaviors at runtime
  • More readable, composable, and flexible
  • Promotes the power of behavior as data.

Real-World Example: Choosing Payment Strategy in an App

Java
 
Map<String, Runnable> paymentStrategies = Map.of(
    "CARD", () -> System.out.println("Processing via Credit Card"),
    "UPI", () -> System.out.println("Processing via UPI"),
    "CASH", () -> System.out.println("Processing via Cash")
);

String chosen = "UPI";
paymentStrategies.get(chosen).run(); // Output: Processing via UPI


Po: “This is amazing! It’s like picking dumplings from a basket, but each dumpling is a deadly move.” 

Shifu: “Exactly. The Strategy was never about the class, Po. It was about choosing the right move at the right moment… effortlessly.” 

One move = One lambda.

The good part is, this lambda only holds the move details—nothing else. So any warrior can master these moves and use them when needed, without having to rely on some bounded object that wrapped the move inside a bulky, boilerplate class.

Final Words of Wisdom  

“The strength of a great developer lies not in how many patterns they know… but in how effortlessly they flow between object thinking and function weaving to craft code that adapts like water, yet strikes like steel.”- Master Shifu, on the Tao of Design Patterns.

Coming Up in the Series

  • Code of Shadows: Master Shifu and Po Use Functional Java to Solve the Decorator Pattern Mystery
  • Kung Fu Commands: Shifu Teaches Po the Command Pattern with Java Functional Interfaces
Functional programming Strategy pattern Java (programming language)

Published at DZone with permission of Shaamik Mitraa, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Related

  • Beyond Java Streams: Exploring Alternative Functional Programming Approaches in Java
  • Redefining Java Object Equality
  • Java vs. Scala: Comparative Analysis for Backend Development in Fintech
  • Singleton: 6 Ways To Write and Use in Java Programming

Partner Resources

×

Comments

The likes didn't load as expected. Please refresh the page and try again.

ABOUT US

  • About DZone
  • Support and feedback
  • Community research
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Core Program
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 3343 Perimeter Hill Drive
  • Suite 100
  • Nashville, TN 37211
  • [email protected]

Let's be friends: