This commit is contained in:
Matt Zhang 2019-05-18 19:22:04 +10:00
commit 599cd1cc24
21 changed files with 5544 additions and 57 deletions

View File

@ -0,0 +1,15 @@
package com.baeldung.ddd.order.doubledispatch;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
public class AmountBasedDiscountPolicy implements DiscountPolicy {
@Override
public double discount(Order order) {
if (order.totalCost()
.isGreaterThan(Money.of(CurrencyUnit.USD, 500.00))) {
return 0.10;
} else
return 0;
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.ddd.order.doubledispatch;
public interface DiscountPolicy {
double discount(Order order);
}

View File

@ -0,0 +1,8 @@
package com.baeldung.ddd.order.doubledispatch;
public class FlatDiscountPolicy implements DiscountPolicy {
@Override
public double discount(Order order) {
return 0.01;
}
}

View File

@ -0,0 +1,29 @@
package com.baeldung.ddd.order.doubledispatch;
import java.math.RoundingMode;
import java.util.List;
import org.joda.money.Money;
import com.baeldung.ddd.order.OrderLine;
import com.baeldung.ddd.order.doubledispatch.visitor.OrderVisitor;
import com.baeldung.ddd.order.doubledispatch.visitor.Visitable;
public class Order extends com.baeldung.ddd.order.Order implements Visitable<OrderVisitor> {
public Order(List<OrderLine> orderLines) {
super(orderLines);
}
public Money totalCost(SpecialDiscountPolicy discountPolicy) {
return totalCost().multipliedBy(1 - applyDiscountPolicy(discountPolicy), RoundingMode.HALF_UP);
}
protected double applyDiscountPolicy(SpecialDiscountPolicy discountPolicy) {
return discountPolicy.discount(this);
}
@Override
public void accept(OrderVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,5 @@
package com.baeldung.ddd.order.doubledispatch;
public interface SpecialDiscountPolicy extends DiscountPolicy {
double discount(SpecialOrder order);
}

View File

@ -0,0 +1,36 @@
package com.baeldung.ddd.order.doubledispatch;
import java.util.List;
import com.baeldung.ddd.order.OrderLine;
import com.baeldung.ddd.order.doubledispatch.visitor.OrderVisitor;
public class SpecialOrder extends Order {
private boolean eligibleForExtraDiscount;
public SpecialOrder(List<OrderLine> orderLines) {
super(orderLines);
this.eligibleForExtraDiscount = false;
}
public SpecialOrder(List<OrderLine> orderLines, boolean eligibleForSpecialDiscount) {
super(orderLines);
this.eligibleForExtraDiscount = eligibleForSpecialDiscount;
}
public boolean isEligibleForExtraDiscount() {
return eligibleForExtraDiscount;
}
@Override
protected double applyDiscountPolicy(SpecialDiscountPolicy discountPolicy) {
return discountPolicy.discount(this);
}
@Override
public void accept(OrderVisitor visitor) {
visitor.visit(this);
}
}

View File

@ -0,0 +1,24 @@
package com.baeldung.ddd.order.doubledispatch.visitor;
import com.baeldung.ddd.order.doubledispatch.Order;
import com.baeldung.ddd.order.doubledispatch.SpecialOrder;
public class HtmlOrderViewCreator implements OrderVisitor {
private String html;
public String getHtml() {
return html;
}
@Override
public void visit(Order order) {
html = String.format("<p>Regular order total cost: %s</p>", order.totalCost());
}
@Override
public void visit(SpecialOrder order) {
html = String.format("<h1>Special Order</h1><p>total cost: %s</p>", order.totalCost());
}
}

View File

@ -0,0 +1,9 @@
package com.baeldung.ddd.order.doubledispatch.visitor;
import com.baeldung.ddd.order.doubledispatch.Order;
import com.baeldung.ddd.order.doubledispatch.SpecialOrder;
public interface OrderVisitor {
void visit(Order order);
void visit(SpecialOrder order);
}

View File

@ -0,0 +1,5 @@
package com.baeldung.ddd.order.doubledispatch.visitor;
public interface Visitable<V> {
void accept(V visitor);
}

View File

@ -92,7 +92,7 @@ class JpaOrder {
}
void removeLineItem(int line) {
JpaOrderLine removedLine = orderLines.remove(line);
orderLines.remove(line);
}
void setCurrencyUnit(String currencyUnit) {

View File

@ -15,7 +15,7 @@ class JpaProduct {
public JpaProduct(BigDecimal price, String currencyUnit) {
super();
this.price = price;
currencyUnit = currencyUnit;
this.currencyUnit = currencyUnit;
}
@Override

View File

@ -0,0 +1,17 @@
package com.baeldung.ddd.order;
import java.util.Arrays;
import java.util.List;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
public class OrderFixtureUtils {
public static List<OrderLine> anyOrderLines() {
return Arrays.asList(new OrderLine(new Product(Money.of(CurrencyUnit.USD, 100)), 1));
}
public static List<OrderLine> orderLineItemsWorthNDollars(int totalCost) {
return Arrays.asList(new OrderLine(new Product(Money.of(CurrencyUnit.USD, totalCost)), 1));
}
}

View File

@ -0,0 +1,77 @@
package com.baeldung.ddd.order.doubledispatch;
import static org.assertj.core.api.Assertions.assertThat;
import org.joda.money.CurrencyUnit;
import org.joda.money.Money;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.baeldung.ddd.order.OrderFixtureUtils;
public class DoubleDispatchDiscountPolicyUnitTest {
// @formatter:off
@DisplayName(
"given regular order with items worth $100 total, " +
"when apply 10% discount policy, " +
"then cost after discount is $90"
)
// @formatter:on
@Test
void test() throws Exception {
// given
Order order = new Order(OrderFixtureUtils.orderLineItemsWorthNDollars(100));
SpecialDiscountPolicy discountPolicy = new SpecialDiscountPolicy() {
@Override
public double discount(Order order) {
return 0.10;
}
@Override
public double discount(SpecialOrder order) {
return 0;
}
};
// when
Money totalCostAfterDiscount = order.totalCost(discountPolicy);
// then
assertThat(totalCostAfterDiscount).isEqualTo(Money.of(CurrencyUnit.USD, 90));
}
// @formatter:off
@DisplayName(
"given special order eligible for extra discount with items worth $100 total, " +
"when apply 20% discount policy for extra discount orders, " +
"then cost after discount is $80"
)
// @formatter:on
@Test
void test1() throws Exception {
// given
boolean eligibleForExtraDiscount = true;
Order order = new SpecialOrder(OrderFixtureUtils.orderLineItemsWorthNDollars(100), eligibleForExtraDiscount);
SpecialDiscountPolicy discountPolicy = new SpecialDiscountPolicy() {
@Override
public double discount(Order order) {
return 0;
}
@Override
public double discount(SpecialOrder order) {
if (order.isEligibleForExtraDiscount())
return 0.20;
return 0.10;
}
};
// when
Money totalCostAfterDiscount = order.totalCost(discountPolicy);
// then
assertThat(totalCostAfterDiscount).isEqualTo(Money.of(CurrencyUnit.USD, 80.00));
}
}

View File

@ -0,0 +1,43 @@
package com.baeldung.ddd.order.doubledispatch;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.Arrays;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.baeldung.ddd.order.doubledispatch.Order;
import com.baeldung.ddd.order.OrderFixtureUtils;
import com.baeldung.ddd.order.OrderLine;
import com.baeldung.ddd.order.doubledispatch.visitor.HtmlOrderViewCreator;
public class HtmlOrderViewCreatorUnitTest {
// @formatter:off
@DisplayName(
"given collection of regular and special orders, " +
"when create HTML view using visitor for each order, " +
"then the dedicated view is created for each order"
)
// @formatter:on
@Test
void test() throws Exception {
// given
List<OrderLine> anyOrderLines = OrderFixtureUtils.anyOrderLines();
List<Order> orders = Arrays.asList(new Order(anyOrderLines), new SpecialOrder(anyOrderLines));
HtmlOrderViewCreator htmlOrderViewCreator = new HtmlOrderViewCreator();
// when
orders.get(0)
.accept(htmlOrderViewCreator);
String regularOrderHtml = htmlOrderViewCreator.getHtml();
orders.get(1)
.accept(htmlOrderViewCreator);
String specialOrderHtml = htmlOrderViewCreator.getHtml();
// then
assertThat(regularOrderHtml).containsPattern("<p>Regular order total cost: .*</p>");
assertThat(specialOrderHtml).containsPattern("<h1>Special Order</h1><p>total cost: .*</p>");
}
}

View File

@ -0,0 +1,50 @@
package com.baeldung.ddd.order.doubledispatch;
import static org.assertj.core.api.Assertions.assertThat;
import java.util.List;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.baeldung.ddd.order.doubledispatch.Order;
import com.baeldung.ddd.order.OrderFixtureUtils;
import com.baeldung.ddd.order.OrderLine;
import com.baeldung.ddd.order.doubledispatch.SpecialDiscountPolicy;
import com.baeldung.ddd.order.doubledispatch.SpecialOrder;
public class MethodOverloadExampleUnitTest {
// @formatter:off
@DisplayName(
"given discount policy accepting special orders, " +
"when apply the policy on special order declared as regular order, " +
"then regular discount method is used"
)
// @formatter:on
@Test
void test() throws Exception {
// given
SpecialDiscountPolicy specialPolicy = new SpecialDiscountPolicy() {
@Override
public double discount(Order order) {
return 0.01;
}
@Override
public double discount(SpecialOrder order) {
return 0.10;
}
};
Order specialOrder = new SpecialOrder(anyOrderLines());
// when
double discount = specialPolicy.discount(specialOrder);
// then
assertThat(discount).isEqualTo(0.01);
}
private List<OrderLine> anyOrderLines() {
return OrderFixtureUtils.anyOrderLines();
}
}

View File

@ -0,0 +1,37 @@
package com.baeldung.ddd.order.doubledispatch;
import static org.assertj.core.api.Assertions.assertThat;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import com.baeldung.ddd.order.OrderFixtureUtils;
public class SingleDispatchDiscountPolicyUnitTest {
// @formatter:off
@DisplayName(
"given two discount policies, " +
"when use these policies, " +
"then single dispatch chooses the implementation based on runtime type"
)
// @formatter:on
@Test
void test() throws Exception {
// given
DiscountPolicy flatPolicy = new FlatDiscountPolicy();
DiscountPolicy amountPolicy = new AmountBasedDiscountPolicy();
Order orderWorth501Dollars = orderWorthNDollars(501);
// when
double flatDiscount = flatPolicy.discount(orderWorth501Dollars);
double amountDiscount = amountPolicy.discount(orderWorth501Dollars);
// then
assertThat(flatDiscount).isEqualTo(0.01);
assertThat(amountDiscount).isEqualTo(0.1);
}
private Order orderWorthNDollars(int totalCost) {
return new Order(OrderFixtureUtils.orderLineItemsWorthNDollars(totalCost));
}
}

View File

@ -15,28 +15,6 @@
</parent>
<dependencies>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>${commons-io.version}</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>${commons-codec.version}</version>
</dependency>
<!-- test scoped -->
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core</artifactId>
<version>${assertj.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
@ -57,11 +35,6 @@
<artifactId>guava</artifactId>
<version>${guava.version}</version>
</dependency>
<dependency>
<groupId>com.vdurmont</groupId>
<artifactId>emoji-java</artifactId>
<version>${emoji-java.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
@ -73,38 +46,18 @@
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit-jupiter-api.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest-library</artifactId>
<version>${org.hamcrest.version}</version>
<scope>test</scope>
</dependency>
<!-- Added for password generation -->
<dependency>
<groupId>org.passay</groupId>
<artifactId>passay</artifactId>
<version>${passay.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-text</artifactId>
<version>${commons-text.version}</version>
</dependency>
<dependency>
<groupId>org.ahocorasick</groupId>
<artifactId>ahocorasick</artifactId>
<version>${ahocorasick.version}</version>
</dependency>
</dependencies>
<build>
@ -131,18 +84,10 @@
</build>
<properties>
<!-- util -->
<commons-lang3.version>3.8.1</commons-lang3.version>
<commons-codec.version>1.10</commons-codec.version>
<!-- testing -->
<assertj.version>3.6.1</assertj.version>
<icu4j.version>61.1</icu4j.version>
<guava.version>27.0.1-jre</guava.version>
<emoji-java.version>4.0.0</emoji-java.version>
<junit-jupiter-api.version>5.3.1</junit-jupiter-api.version>
<passay.version>1.3.1</passay.version>
<commons-text.version>1.4</commons-text.version>
<ahocorasick.version>0.4.0</ahocorasick.version>
</properties>
</project>

View File

@ -0,0 +1,73 @@
package com.baeldung.string.performance;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.BenchmarkMode;
import org.openjdk.jmh.annotations.Fork;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.OutputTimeUnit;
import org.openjdk.jmh.annotations.Scope;
import org.openjdk.jmh.annotations.Setup;
import org.openjdk.jmh.annotations.State;
@Fork(value = 3, warmups = 1)
@State(Scope.Benchmark)
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
public class RemovingStopwordsPerformanceComparison {
private String data;
private List<String> stopwords;
private String stopwordsRegex;
public static void main(String[] args) throws Exception {
org.openjdk.jmh.Main.main(args);
}
@Setup
public void setup() throws IOException {
data = new String(Files.readAllBytes(Paths.get("src/main/resources/shakespeare-hamlet.txt")));
data = data.toLowerCase();
stopwords = Files.readAllLines(Paths.get("src/main/resources/english_stopwords.txt"));
stopwordsRegex = stopwords.stream().collect(Collectors.joining("|", "\\b(", ")\\b\\s?"));
}
@Benchmark
public String removeManually() {
String[] allWords = data.split(" ");
StringBuilder builder = new StringBuilder();
for(String word:allWords) {
if(! stopwords.contains(word)) {
builder.append(word);
builder.append(' ');
}
}
return builder.toString().trim();
}
@Benchmark
public String removeAll() {
ArrayList<String> allWords = Stream.of(data.split(" "))
.collect(Collectors.toCollection(ArrayList<String>::new));
allWords.removeAll(stopwords);
return allWords.stream().collect(Collectors.joining(" "));
}
@Benchmark
public String replaceRegex() {
return data.replaceAll(stopwordsRegex, "");
}
}

View File

@ -0,0 +1,127 @@
i
me
my
myself
we
our
ours
ourselves
you
your
yours
yourself
yourselves
he
him
his
himself
she
her
hers
herself
it
its
itself
they
them
their
theirs
themselves
what
which
who
whom
this
that
these
those
am
is
are
was
were
be
been
being
have
has
had
having
do
does
did
doing
a
an
the
and
but
if
or
because
as
until
while
of
at
by
for
with
about
against
between
into
through
during
before
after
above
below
to
from
up
down
in
out
on
off
over
under
again
further
then
once
here
there
when
where
why
how
all
any
both
each
few
more
most
other
some
such
no
nor
not
only
own
same
so
than
too
very
s
t
can
will
just
don
should
now

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,60 @@
package com.baeldung.string;
import static org.junit.Assert.assertEquals;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.junit.BeforeClass;
import org.junit.Test;
public class RemoveStopwordsUnitTest {
final String original = "The quick brown fox jumps over the lazy dog";
final String target = "quick brown fox jumps lazy dog";
static List<String> stopwords;
@BeforeClass
public static void loadStopwords() throws IOException {
stopwords = Files.readAllLines(Paths.get("src/main/resources/english_stopwords.txt"));
}
@Test
public void whenRemoveStopwordsManually_thenSuccess() {
String[] allWords = original.toLowerCase()
.split(" ");
StringBuilder builder = new StringBuilder();
for (String word : allWords) {
if (!stopwords.contains(word)) {
builder.append(word);
builder.append(' ');
}
}
String result = builder.toString().trim();
assertEquals(result, target);
}
@Test
public void whenRemoveStopwordsUsingRemoveAll_thenSuccess() {
ArrayList<String> allWords = Stream.of(original.toLowerCase()
.split(" "))
.collect(Collectors.toCollection(ArrayList<String>::new));
allWords.removeAll(stopwords);
String result = allWords.stream().collect(Collectors.joining(" "));
assertEquals(result, target);
}
@Test
public void whenRemoveStopwordsUsingRegex_thenSuccess() {
String stopwordsRegex = stopwords.stream()
.collect(Collectors.joining("|", "\\b(", ")\\b\\s?"));
String result = original.toLowerCase().replaceAll(stopwordsRegex, "");
assertEquals(result, target);
}
}