一、Factory Method Pattern
当client不知道或不确定要创建哪个具体类的实例,或者不想再client代码中知名要具体创建的实例时,用工厂方法。
定义一个用于创建对象的接口,让该接口的子类型来决定实例化哪一个类,从而使一个类的实例化延迟到其子类。
工厂接口及其实现类:
interface TraceFactory{
Trace getTrace();
...
}
public class SystemTraceFactory implements TraceFactory{
public Trace getTrace(){
...
return new SystemTrace();
}
}
public class FileTraceFactory implements TraceFactory{
public Trace getTrace(){
...
return new FileTraceFactory();
}
}
client:
Trace log1 = new SystemTraceFactory().getTrace();
Trace log2 = new FileTraceFactory().getTrace();
二、Adaptor Pattern
当某个类的某个方法和client期望的形式冲突时,可以使用Adaptor模式添加适配器。
如LegacyRectangle类的display(x,y,w,h)方法,四个参数分别表示左上角的坐标、宽、高,而client希望它们表示的是左上角坐标和右上角坐标,这时就可以为display方法添加一个适配器。
如下,ShapeAdaptor接口中定义需要适配的方法,Rectangle类按client的要求实现该接口中的方法,client使用适配器访问该方法,这样无需修改原LegacyRectangle类就可以做出功能上的改变。若display有多个版本,则为ShapeAdaptor增加子类,在子类中实现各版本。
interface ShapeAdaptor{
void display(int x1, int y1, int x2, int y2);
}
class Rectangle implements Shape {
void display(int x1, int y1, int x2, int y2) {
new LegacyRectangle().display(x1, y1, x2-x1, y2-y1);
}
}
class LegacyRectangle {
void display(int x1, int y1, int w, int h) {...}
}
class Client {
Shape shape = new Rectangle();
public display() {
shape.display(x1, y1, x2, y2);
}
}
三、Decorator
接口IceCream和它的实现类PlainIceCream,接口定义了一个方法AddTopping,现要扩展AddTopping的功能。可以先定义一个装饰器基类ToppingDecorator,再为各个版本定义子类,子类中通过委派的方式使用原始版本的方法,在其基础上增加一些操作。
装饰器的有一个input域,可以赋值为原始类,也可以赋值为装饰类,这是递归的形式。
public interface IceCream {
//顶层接口
void AddTopping();
}
public class PlainIceCream implements IceCream{
//基础实现,无填加的冰激凌
@Override
public void AddTopping() {
System.out.println("Plain IceCream ready for some toppings!");
}
}
/*装饰器基类*/
public abstract class ToppingDecorator implements IceCream{
protected final IceCream input;
public ToppingDecorator(IceCream i){
this.input = i;
}
public abstract void AddTopping();
}
/*子类1*/
public class CandyTopping extends ToppingDecorator{
public CandyTopping(IceCream i) {
super(i);
}
public void AddTopping() {
input.AddTopping();
System.out.println("Candy Topping added!");
}
}
/*子类2,3*/
public class NutsTopping extends ToppingDecorator{
//similar to CandyTopping
}
public class PeanutTopping extends ToppingDecorator{
//similar to CandyTopping
}
client根据需要选择装饰器:
IceCream toppingIceCream =
new NutsTopping(
new PeanutTopping(
new CandyTopping(
new PlainIceCream()
)
)
);
toppingIceCream.AddTopping();
四、Strategy Pattern
某个方法有多种实现,client需要动态切换实现方式。
现要将类ShoppingCart的pay方法实现为多个版本,创建Strategy接口,定义pay方法,然后在该接口的实现类中实现pay的多个版本,让ShoppingCart类的pay方法接收Strategy实例,调用相应Strategy的pay方法。
public class ShoppingCart {
...
public void pay(PaymentStrategy paymentMethod){
...
paymentMethod.pay(amount);
}
}
public interface PaymentStrategy {
public void pay(int amount);
}
public class PaypalStrategy implements PaymentStrategy {
...
@Override
public void pay(int amount) {
//实现方法一
System.out.println(amount + " paid using Paypal.");
}
}
public class CashStrategy implements PaymentStrategy {
...
@Override
public void pay(int amount) {
//实现方法二
System.out.println(amount + " paid using Cash.");
}
}
client通过向pay传递Strategy的方式切换不同实现:
ShoppingCart cart = new ShoppingCart();
...
cart.pay(new PaypalStrategy(...));
cart.pay(new CashStrategy(...));
五、Template Method
若某些类的实现过程步骤相同,只是各个步骤的实现不同,那么就可以将这个步骤抽象成一个接口。
如接口CarBuilder中定义了三个步骤和一个通用逻辑指示这些步骤的执行顺序,实现类中实现步骤的不同版本。
public abstract class CarBuilder {
protected abstract void BuildSkeleton();
protected abstract void InstallEngine();
protected abstract void InstallDoor();
// Template Method that specifies the general logic
public void BuildCar() {
//通用逻辑
BuildSkeleton(); InstallEngine(); InstallDoor();
}
}
public class PorcheBuilder extends CarBuilder {
protected void BuildSkeleton() {
System.out.println("Building Porche Skeleton");
}
protected void InstallEngine() {
System.out.println("Installing Porche Engine");
}
protected void InstallDoor() {
System.out.println("Installing Porche Door");
}
}
public class BeetleBuilder extends CarBuilder {
protected void BuildSkeleton() {
System.out.println("Building Beetle Skeleton");
}
protected void InstallEngine() {
System.out.println("Installing Beetle Engine");
}
protected void InstallDoor() {
System.out.println("Installing Beetle Door");
}
}
client:
CarBuilder c = new PorcheBuilder();
c.BuildCar();
c = new BeetleBuilder();
c.BuildCar();
六、Iterator Pattern
将某一个类实现为可迭代类。
MyArray类实现Iterable接口,重写iterator方法,返回一个迭代器;
MyIterator为一个自定义迭代器,实现Iterator接口的next、hasNext方法。
public class MyArray<E> implements Iterable<E> {
private final List<E> list;
public MyArray(List<E> list) {
this.list = new ArrayList<E>(list);
}
public MyArray() {
list = new ArrayList<>();
}
@Override
public Iterator<E> iterator() {
return new MyIterator();
}
private class MyIterator implements Iterator<E> {
private int index;
public MyIterator() {
index = 0;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public E next() {
E element = list.get(index);
index++;
return element;
}
}
}
client:
public static void main(String[] args) {
List<String> list = new ArrayList<>();
list.add("a");
list.add("b");
list.add("c");
MyArray<String> mi = new MyArray<>(list);
for (String s : mi) {
System.out.println(s);
}
}
七、Vistor Pattern
某个类需要多种访问方式。根据需要访问的类抽象出一个接口Item,定义accept方法,然后将访问者抽象成接口Vistor,定义visit方法,overload多种版本,可访问类实现Item,访问类实现Vistor中的不同访问方法。
public interface ItemElement {
public int accept(ShoppingCartVisitor visitor);
}
/* Concrete element */
public class Book implements ItemElement{
private double price;
...
int accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
public class Fruit implements ItemElement{
private double weight;
...
int accept(ShoppingCartVisitor visitor) {
visitor.visit(this);
}
}
public interface ShoppingCartVisitor {
int visit(Book book);
int visit(Fruit fruit);
}
public class ShoppingCartVisitorImpl implements ShoppingCartVisitor {
public int visit(Book book) {
int cost=0;
if(book.getPrice() > 50){
cost = book.getPrice()-5;
}else
cost = book.getPrice();
System.out.println("Book ISBN::"+book.getIsbnNumber() + " cost ="+cost);
return cost;
}
public int visit(Fruit fruit) {
int cost = fruit.getPricePerKg()*fruit.getWeight();
System.out.println(fruit.getName() + " cost = "+cost);
return cost;
}
}
client:
List<ItemElement>list = new ArrayList<>();
list.add(new Book(20 , "12"));
list.add(new Fruit(5 , 5 , "apple"));
ShoppingCartVisitor visitor = new ShoppingCartVisitorImpl();
int sum = 0;
for(ItemElement item : list){
sum += item.accept(visitor);
return sum;
}