Saturday, 1 February 2014

State Design pattern - Implementation [Project]

Master Hands-On Java Architecture & Patterns!

Subscribe to Ram N Java for clean code walkthroughs, design pattern implementations, and step-by-step project builds!

🔔 Subscribe to Ram N Java

Managing Complex State Lifecycles in Real Projects

In software development projects, domain entities frequently transition through intricate multi-stage lifecycles. Whether you are building an order processing system, an approval workflow, or a document management engine, objects change their behavior dramatically based on their current stage.

Relying on flag variables and nested switch-case statements leads to brittle code that is prone to regression bugs whenever a new lifecycle phase is introduced. The State Design Pattern provides an object-oriented solution by turning states into independent classes.

Project Implementation Architecture

In this end-to-end project walkthrough, the architecture is structured around clean object-oriented delegation:

  • State Interface: Outlines the contract and domain actions valid across various lifecycle phases.
  • Concrete State Classes: Each state class encapsulates the exact logic for handling incoming requests and controls transitions to subsequent states.
  • Context Class: Maintains a reference to the active state instance and delegates operational methods directly to it, decoupling the consumer from state transition logic.

Architectural Benefits in Production Code

Applying the State pattern to real-world applications delivers clear advantages:

  • Open/Closed Principle: Introduce new project states or lifecycle steps by creating new classes without altering existing state code.
  • Single Responsibility Principle: Isolate state-specific execution logic into dedicated files for simpler unit testing and debugging.
  • Cleaner Domain Models: Remove convoluted conditionals, replacing them with expressive, polymorphic method dispatch.

Related Tutorials from Ram N Java


Click here to watch in Youtube : https://www.youtube.com/watch?v=RDANwlKtN6E

Click the below Image to Enlarge
State Design pattern - Implementation [Project]


State Design pattern - Implementation [Project] - Class Diagram












































ProjectState.java

public interface ProjectState
{

public void doRequirmentGathering();

public void doDesignAndArchitecture();

public void doDevelopement();

public void doTesting();


}

RequirementGatheringState.java

public class RequirementGatheringState implements ProjectState
{

@Override
public void doRequirmentGathering()
{
System.out.println("'RequirmentGathering' has been started .............");

System.out.println("'RequirmentGathering' has been finished by 7 days .............");

}

@Override
public void doDesignAndArchitecture()
{
System.out.println("Cannot do 'DesignAndArchitecture' because Project is in 'RequirmentGathering' Phase...");

}

@Override
public void doDevelopement()
{
System.out.println("Cannot do 'developement' because Project is in 'RequirmentGathering' Phase...");

}

@Override
public void doTesting()
{
System.out.println("Cannot do 'Testing' because Project is in 'RequirmentGathering' Phase...");

}

}

DesignAndArchitectureState.java

public class DesignAndArchitectureState implements ProjectState
{
@Override
public void doRequirmentGathering()
{
System.out.println("'RequirmentGathering'[Clarification of Requirement] you can do in ''DesignAndArchitecture'' Phase .......");
}

@Override
public void doDesignAndArchitecture()
{
System.out.println("'DesignAndArchitecture' has been started .............");

System.out.println("'DesignAndArchitecture' has been finished by 10 days .............");
}

@Override
public void doDevelopement()
{
System.out.println("Cannot do 'developement' because Project is in 'DesignAndArchitecture' Phase...");

}

@Override
public void doTesting()
{
System.out.println("Cannot do 'Testing' because Project is in 'DesignAndArchitecture' Phase...");

}

}

DevelopementState.java

public class DevelopementState implements ProjectState
{
@Override
public void doRequirmentGathering()
{
System.out.println("Cannot do 'RequirmentGathering' because Project is in 'Developement' Phase...");
}

@Override
public void doDesignAndArchitecture()
{
System.out.println("'DesignAndArchitecture'[Clarification of DesignAndArchitecture] you can do in ''Developement'' Phase .......");
}

@Override
public void doDevelopement()
{
System.out.println("'Developement' has been started .............");

System.out.println("'Developement' has been finished by 40 days .............");

}

@Override
public void doTesting()
{
System.out.println("Cannot do 'Testing' because Project is in 'Developement' Phase...");

}

}

TestingState.java

public class TestingState implements ProjectState
{
@Override
public void doRequirmentGathering()
{
System.out.println("Cannot do 'RequirmentGathering' because Project is in 'Testing' Phase...");
}

@Override
public void doDesignAndArchitecture()
{
System.out.println("Cannot do 'DesignAndArchitecture' because Project is in 'Testing' Phase...");
}

@Override
public void doDevelopement()
{
System.out.println("'Developement'[Bug fixes] you can do in ''Testing'' Phase .......");

}

@Override
public void doTesting()
{
System.out.println("'Testing' has been started .............");

System.out.println("'Testing' has been finished by 20 days .............");

}

}

Project.java

// This is like Context
public class Project implements ProjectState
{

private ProjectState projectState;

public Project()
{
projectState = new RequirementGatheringState();
}

public ProjectState getProjectState()
{
return projectState;
}

public void setProjectState( ProjectState projectState )
{
this.projectState = projectState;
}

@Override
public void doRequirmentGathering()
{
projectState.doRequirmentGathering();
/*
* Once RequirmentGathering is finished project internal state
* will be moved to DesignAndArchitectureState
*/
if( projectState instanceof RequirementGatheringState )
{
setProjectState(new DesignAndArchitectureState());
System.out.println("\nProject internal state moved to : " + projectState.getClass().getName() +"\n" );
}

}

@Override
public void doDesignAndArchitecture()
{
projectState.doDesignAndArchitecture();

/*
* Once DesignAndArchitecture is finished project internal state
* will be moved to DevelopementState
*/
if( projectState instanceof DesignAndArchitectureState )
{
setProjectState(new DevelopementState());
System.out.println("\nProject internal state moved to : " + projectState.getClass().getName() +"\n" );
}

}

@Override
public void doDevelopement()
{
projectState.doDevelopement();

/*
* Once Developement is finished project internal state will be
* moved to TestingState
*/

if( projectState instanceof DevelopementState )
{
setProjectState(new TestingState());
System.out.println("\nProject internal state moved to : " + projectState.getClass().getName() +"\n" );
}

}

@Override
public void doTesting()
{
projectState.doTesting();

}

}

Client.java

public class Client
{

public static void main( String[] args )
{
/*
* Initially Project in 'RequirementGatheringState'
*/
Project project = new Project();

System.out.println("Project internal state is  : " + project.getProjectState().getClass().getName()+"\n");

project.doDesignAndArchitecture();
project.doDevelopement();
project.doTesting();
project.doRequirmentGathering();

System.out.println();

project.doDesignAndArchitecture();
project.doTesting();
project.doDevelopement();
project.doRequirmentGathering();

}

}

Output

Project internal state is  : RequirementGatheringState

Cannot do 'DesignAndArchitecture' because Project is in 'RequirmentGathering' Phase...
Cannot do 'developement' because Project is in 'RequirmentGathering' Phase...
Cannot do 'Testing' because Project is in 'RequirmentGathering' Phase...
'RequirmentGathering' has been started .............
'RequirmentGathering' has been finished by 7 days .............

Project internal state moved to : DesignAndArchitectureState


'DesignAndArchitecture' has been started .............
'DesignAndArchitecture' has been finished by 10 days .............

Project internal state moved to : DevelopementState

Cannot do 'Testing' because Project is in 'Developement' Phase...
'Developement' has been started .............
'Developement' has been finished by 40 days .............

Project internal state moved to : TestingState

Cannot do 'RequirmentGathering' because Project is in 'Testing' Phase...

See also:

  • State Design pattern - Introduction
  • State Design pattern - Real time example [ATM]
  • State Design pattern - Real time example [TV Remote]
  • State Design pattern - Real time example [Vending Machine]
  • State Design pattern - Real time example [Project]
  • State Design pattern - Class Diagram
  • State Design pattern - Implementation [ATM]
  • State Design pattern - Implementation [Vending Machine]
  • State Design pattern - Implementation [LED TV]
  • State Design pattern - Keypoints
  • All Design Patterns Links
  • No comments:

    Post a Comment

    Tutorials