MaterialStore.java
package com.university.bookstore.api;
import java.util.List;
import java.util.Optional;
import java.util.function.Predicate;
import com.university.bookstore.model.Material;
import com.university.bookstore.model.Media;
/**
* Interface defining operations for a polymorphic material store that demonstrates interface segregation and
* dependency inversion principles. Compare to {@link BookstoreAPI}, this interface is extensible to other types of materials.
*
* <p>The Interface Segregation Principle (ISP) states that clients should not be forced to depend on interfaces they
* do not use. In practice, this means designing smaller, more focused interfaces rather than large, monolithic ones.
* For example, instead of creating a single Machine interface with methods like print(), scan(), and fax(), which
* every implementation must support, ISP encourages splitting these into multiple role-specific interfaces (Printer,
* Scanner, FaxMachine). This ensures that implementing classes only provide the functionality relevant to them,
* leading to higher cohesion, reduced coupling, and easier maintenance. ISP directly combats the rigidity and
* fragility that arise when changes in unused methods propagate across unrelated parts of the system.</p>
*
* <p>The Dependency Inversion Principle (DIP) requires that high-level modules depend on abstractions, not concrete
* implementations. Instead of having business logic directly tied to low-level details (like a specific database
* driver or logging mechanism), DIP advocates for using interfaces or abstract classes as boundaries. For instance,
* a PaymentService should rely on a PaymentProcessor interface rather than a hardcoded StripeProcessor. This allows
* developers to substitute implementations without altering higher-level policies, supporting testability,
* scalability, and adaptability to new technologies. By inverting the dependency direction, DIP ensures that both
* high- and low-level modules evolve independently, fostering loosely coupled, extensible architectures.</p>
*
* <p>This interface extends the concept of a bookstore to handle
* various types of materials using polymorphism.</p>
*
* @author Navid Mohaghegh
* @version 2.0
* @since 2024-09-15
*/
public interface MaterialStore {
/**
* Adds a material to the store inventory.
*
* @param material the material to add
* @return true if added successfully, false if duplicate ID
*/
boolean addMaterial(Material material);
/**
* Removes a material by its ID.
*
* @param id the material ID
* @return the removed material, or Optional.empty() if not found
*/
Optional<Material> removeMaterial(String id);
/**
* Finds a material by its ID.
*
* @param id the material ID
* @return the material, or Optional.empty() if not found
*/
Optional<Material> findById(String id);
/**
* Searches materials by title (case-insensitive partial match).
*
* @param title the title to search for
* @return list of matching materials
*/
List<Material> searchByTitle(String title);
/**
* Searches materials by creator (author/director/publisher).
*
* @param creator the creator name
* @return list of matching materials
*/
List<Material> searchByCreator(String creator);
/**
* Gets all materials of a specific type.
* Demonstrates polymorphic filtering.
*
* @param type the material type
* @return list of materials of the specified type
*/
List<Material> getMaterialsByType(Material.MaterialType type);
/**
* Gets all materials that implement the Media interface.
* Demonstrates interface-based polymorphism.
*
* @return list of media materials
*/
List<Media> getMediaMaterials();
/**
* Filters materials by a custom predicate.
* Demonstrates functional programming with polymorphism.
*
* @param predicate the filter condition
* @return filtered list of materials
*/
List<Material> filterMaterials(Predicate<Material> predicate);
/**
* Finds materials published in the last N years.
*
* @param years the number of years to look back
* @return list of recent materials
*/
List<Material> findRecentMaterials(int years);
/**
* Finds materials by multiple creators (OR condition).
*
* @param creators the creator names to search for
* @return list of materials by any of the specified creators
*/
List<Material> findByCreators(String... creators);
/**
* Finds materials with custom filtering using predicate.
*
* @param condition the filter condition
* @return filtered list of materials
*/
List<Material> findWithPredicate(Predicate<Material> condition);
/**
* Gets materials sorted by custom comparator.
*
* @param comparator the sorting comparator
* @return sorted list of materials
*/
List<Material> getSorted(java.util.Comparator<Material> comparator);
/**
* Gets materials within a price range.
*
* @param minPrice minimum price (inclusive)
* @param maxPrice maximum price (inclusive)
* @return list of materials in price range
*/
List<Material> getMaterialsByPriceRange(double minPrice, double maxPrice);
/**
* Gets materials published/released in a specific year.
*
* @param year the year
* @return list of materials from that year
*/
List<Material> getMaterialsByYear(int year);
/**
* Gets all materials sorted by title.
*
* @return sorted list of all materials
*/
List<Material> getAllMaterialsSorted();
/**
* Gets all materials (unsorted).
*
* @return list of all materials
*/
List<Material> getAllMaterials();
/**
* Calculates total inventory value.
*
* @return sum of all material prices
*/
double getTotalInventoryValue();
/**
* Calculates total discounted inventory value.
* Uses polymorphic discount calculation.
*
* @return sum of all discounted prices
*/
double getTotalDiscountedValue();
/**
* Gets inventory statistics.
*
* @return statistics object with counts and averages
*/
InventoryStats getInventoryStats();
/**
* Clears all materials from the store.
*/
void clearInventory();
/**
* Gets the number of materials in inventory.
*
* @return material count
*/
int size();
/**
* Checks if the inventory is empty.
*
* @return true if no materials in inventory
*/
boolean isEmpty();
/**
* Statistics class for inventory analysis.
*/
class InventoryStats {
private final int totalCount;
private final double averagePrice;
private final double medianPrice;
private final int uniqueTypes;
private final int mediaCount;
private final int printCount;
public InventoryStats(int totalCount, double averagePrice, double medianPrice,
int uniqueTypes, int mediaCount, int printCount) {
this.totalCount = totalCount;
this.averagePrice = averagePrice;
this.medianPrice = medianPrice;
this.uniqueTypes = uniqueTypes;
this.mediaCount = mediaCount;
this.printCount = printCount;
}
public int getTotalCount() {
return totalCount;
}
public double getAveragePrice() {
return averagePrice;
}
public double getMedianPrice() {
return medianPrice;
}
public int getUniqueTypes() {
return uniqueTypes;
}
public int getMediaCount() {
return mediaCount;
}
public int getPrintCount() {
return printCount;
}
@Override
public String toString() {
return String.format("InventoryStats[Total=%d, AvgPrice=$%.2f, MedianPrice=$%.2f, Types=%d, Media=%d, Print=%d]",
totalCount, averagePrice, medianPrice, uniqueTypes, mediaCount, printCount);
}
}
}