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 Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
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
What's in store for DevOps in 2023? Hear from the experts in our "DZone 2023 Preview: DevOps Edition" on Fri, Jan 27!
Save your seat

The Strategy Pattern

Roger Hughes user avatar by
Roger Hughes
·
Apr. 01, 12 · Interview
Like (0)
Save
Tweet
Share
11.91K Views

Join the DZone community and get the full member experience.

Join For Free
In a recent blog on I received a comment from Wojciech Soczyński about how the “strategy” pattern can be used to enforce the Single Responsibility Principle (SRP) when using Tell Don't Ask (TDA). At some point I plan to discuss this further, but first thought that it would be a good idea to define the Strategy Pattern using the ShoppingCart example that I used a couple of weeks ago in my Tell Don’t Ask and its follow up Disassembling Tell Don’t Ask blogs:



First a definition: in the simplest terms, you can define the Strategy Pattern as telling an object to do a job and to do it using ANOTHER object.

To clarify this further I’m going to redesign the ShoppingCart slightly, by giving it a pay()1 method:

public class ShoppingCart {

  private final List<Item> items;

  public ShoppingCart() {
    items = new ArrayList<Item>();
  }

  public void addItem(Item item) {

    items.add(item);
  }

  public double calcTotalCost() {

    double total = 0.0;
    for (Item item : items) {
      total += item.getPrice();
    }

    return total;
  }

  public boolean pay(PaymentMethod method) {

    double totalCost = calcTotalCost();
    return method.pay(totalCost);
  }
}

The thing to notice about the pay() method is that it takes one parameter of type PaymentMethod - it’s the PaymentMethod that’s the “ANOTHER” object in my definition above.

The next thing to do is define the PaymentMethod as an interface. Why an interface? It’s because the power of this technique is that you can decide at run-time which concrete type you’ll pass into the ShoppingCart to make the payment. For example, given the Payment interface:

public interface PaymentMethod {

  public boolean pay(double amount);

}

you can then define any concrete payment object such as a Visa or a MasterCard for example:
public class Visa implements PaymentMethod {

  private final String name;
  private final String cardNumber;
  private final Date expires;

  public Visa(String name, String cardNumber, Date expires) {
    super();
    this.name = name;
    this.cardNumber = cardNumber;
    this.expires = expires;
  }

  @Override
  public boolean pay(double amount) {

    // Open Comms to Visa
    // Verify connection
    // Paybill using these details
    return true; // if payment goes through
  }

}

...and
public class MasterCard implements PaymentMethod {

  private final String name;
  private final String cardNumber;
  private final Date expires;

  public MasterCard(String name, String cardNumber, Date expires) {
    super();
    this.name = name;
    this.cardNumber = cardNumber;
    this.expires = expires;
  }

  @Override
  public boolean pay(double amount) {

    // Open Comms to Mastercard
    // Verify connection
    // Paybill using these details
    return true; // if payment goes through
  }

}

The final thing to do is to demonstrate this with the unit test: payBillUsingVisa
  @Test
  public void payBillUsingVisa() {

    ShoppingCart instance = new ShoppingCart();

    Item a = new Item("gloves", 23.43);
    instance.addItem(a);

    Item b = new Item("hat", 10.99);
    instance.addItem(b);

    Date expiryDate = getCardExpireyDate();
    PaymentMethod visa = new Visa("CaptainDebug", "1234234534564567", expiryDate);

    boolean result = instance.pay(visa);
    assertTrue(result);

  }

  private Date getCardExpireyDate() {
    Calendar cal = Calendar.getInstance();
    cal.clear();
    cal.set(2015, Calendar.JANUARY, 21);
    return cal.getTime();
  }

In the code above, you can see that I’m creating a ShoppingCart and then I add a few items. Finally, I create a new PaymentMethod in the form of a Visa object and inject it into the pay(PaymentMethod method) function, which is the crux of the matter. In a different situation I could have easily created a MasterCard object and used that as a direct replacement for Visa - i.e. the object that which is passed in as an argument is determined at runtime.

And that defines the Strategy pattern, but that's not the end of the blog. If you've ever used Spring, but never heard of the Strategy pattern, all this should feel a little familiar. This is because it turns out that the Guys at Spring use the Strategy Pattern to underpin their whole technology. If I take my example above and make a few slight changes I can come up with:

@Component
public class SpringShoppingCart {

  private final List<Item> items;

  @Autowired
  @Qualifier("Visa")
  private PaymentMethod method;

  public SpringShoppingCart() {
    items = new ArrayList<Item>();
  }

  public void addItem(Item item) {

    items.add(item);
  }

  public double calcTotalCost() {

    double total = 0.0;
    for (Item item : items) {
      total += item.getPrice();
    }

    return total;
  }

  public boolean pay() {

    double totalCost = calcTotalCost();
    return method.pay(totalCost);
  }
}

The only difference between this incarnation and the first one is that the strategy class Visa is injected by Spring when the class is loaded using the @Autowired annotation. To sum this up, I guess guess that this means that the Strategy Pattern is the most popular pattern in the world.


1For the purposes of this discussion I’m assuming that it’s okay for a ShoppingCart to pay for itself, but whether this is correct or not is a whole new blog...
Strategy pattern

Published at DZone with permission of Roger Hughes, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • Internal Components of Apache ZooKeeper and Their Importance
  • AIOps Being Powered by Robotic Data Automation
  • When AI Strengthens Good Old Chatbots: A Brief History of Conversational AI
  • Promises, Thenables, and Lazy-Evaluation: What, Why, How

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

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

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: