赞
踩
将一个类的接口变成客户端所期待的另一种接口,从而时不相匹配的两个类在一起工作。也称为变压器模式、包装模式(包装模式不止这一种)。让两个类可以工作在一起、提高类的复用率、增加透明性、灵活度高。
主要用于项目维护阶段
代码目录如下:
adapter/
├── sadapter // 新增的适配器代码
│ ├── SecondUserAdapter.java
│ ├── SecondUserAddress.java
│ └── SecondUser.java
├── stable // 已经在运行的代码,不可变
│ ├── FirstUser.java
│ └── IFirstUser.java
├── TestAdapter.java // 测试代码
└── updated // 第三方提供的接口,不可变
├── ISecondUserAddress.java
└── ISecondUser.java
正在运行部分:(stable)
public interface IFirstUser { void printInfo(); } public class FirstUser implements IFirstUser { private String username; public FirstUser(String username) { this.username = username; } @Override public void printInfo() { System.out.println(this.username); } }
需求添加部分(updated)
public interface ISecondUser {
void printUsername();
}
public interface ISecondUserAddress {
void printAddress();
}
为此新建适配器,分别新建两个类来实现接口
public class SecondUser implements ISecondUser { private String username; public SecondUser(String name) { this.username = name; } @Override public void printUsername() { System.out.print(username + " "); } } public class SecondUserAddress implements ISecondUserAddress { private String addr; public SecondUserAddress(String address) { this.addr = address; } @Override public void printAddress() { System.out.print(this.addr); } }
适配器持有两个接口的引用,并实现原有接口
public class SecondUserAdapter implements IFirstUser { private ISecondUser iSecondUser; private ISecondUserAddress iSecondUserAddress; public SecondUserAdapter(ISecondUser iSecondUser, ISecondUserAddress iSecondUserAddress) { this.iSecondUser = iSecondUser; this.iSecondUserAddress = iSecondUserAddress; } @Override public void printInfo() { iSecondUser.printUsername(); iSecondUserAddress.printAddress(); } }
测试代码
IFirstUser user1 = new FirstUser("User1");
user1.printInfo();
SecondUserAdapter userAdapter =
new SecondUserAdapter(new SecondUser("User2"),new SecondUserAddress("5 street"));
userAdapter.printInfo();
输出
User1
User2 5 street
降低对象之间的耦合度,进行解耦,便于模块化开发
当某些数据变化时,某些类会做出相应。处理数据的类主动投送消息,感兴趣的类主动订阅消息
Android开发有大量运用,Button控件的点击事件就是一个例子
以Android中Button的监听器为例,设计一个接口作为监听器,回调时利用handler控制调用的线程。
private Handler mMainHandler;
// 在主线程中运行
mMainHandler = new Handler(Looper.getMainLooper());
private void notifySthChange(final int state) {
mMainHandler.post(new Runnable() {
@Override
public void run() {
ArrayList<SListener> list = new ArrayList<>(mListeners);
for(SListener l : list) {
l.OnSthChanged(state);
}
}
});
}
在回调中,可以直接更新UI。
将抽象和现实解耦,可以独立的变化
当一个类内部具备两种或多种变化维度时,使用桥接模式可以解耦这些变化的维度,使高层代码架构稳定
模拟工厂生产销售产品
文件目录
bridge/
|-- Client.java // 测试代码
|-- factory
| |-- CanFactory.java // 罐头工厂
| `-- ModernFactory.java // 现代化工厂
|-- Factory.java // 工厂的抽象类
|-- product
| |-- Can.java // 产品具体类 罐头
| `-- Toy.java // 产品具体类 玩具
`-- Product.java // 产品的抽象类
产品类
public abstract class Product { protected void made() { System.out.println(getClass().getSimpleName() + " has been made"); } protected void sold() { System.out.println(getClass().getSimpleName() + " has been sold"); } } public class Can extends Product { @Override public void made() { super.made(); } @Override public void sold() { super.sold(); } } public class Toy extends Product { @Override public void made() { super.made(); } @Override public void sold() { super.sold(); } }
工厂类
public abstract class Factory { private Product product; // 引用抽象的产品类 public Factory(Product p) { this.product = p; } public void makeMoney() { product.made(); product.sold(); } } public class CanFactory extends Factory { // 只接受Can类 public CanFactory(Can p) { super(p); } @Override public void makeMoney() { super.makeMoney(); System.out.println(getClass().getSimpleName() + " make money!"); } } public class ModernFactory extends Factory { // 只要是Product即可生产 public ModernFactory(Product p) { super(p); } @Override public void makeMoney() { super.makeMoney(); System.out.println("ModernFactory make money!"); } }
罐头工厂CanFactory只能生产罐头Can,而现代工厂ModernFactory可以生产Product,罐头或者玩具都可以。
测试与输出
Can can = new Can();
CanFactory canFactory = new CanFactory(can);
canFactory.makeMoney();
ModernFactory modernFactory = new ModernFactory(new Toy());
modernFactory.makeMoney();
/*
Can has been made
Can has been sold
CanFactory make money!
Toy has been made
Toy has been sold
ModernFactory make money!
*/
将复杂对象的构造与其表示分离,以便相同的构造过程可以创建不同的表示。也成为生成器模式。具有较好的封装性【客户端不必知道模型内部细节】、独立易扩展、方便控制风险
AOSP中的AlertDialog.Builder
AlertDialog采用了Builder模式,通过builder可以对dialog进行配置。其中,dialog的各项属性可以设置默认值。
public class AlertDialog extends Dialog implements DialogInterface {
public static class Builder {
public Builder(Context context) {}
public Builder setTitle(CharSequence title) {}
public Builder setMessage(@StringRes int messageId) {}
public Builder setPositiveButton(@StringRes int textId, final OnClickListener listener) {}
public Builder setNegativeButton(@StringRes int textId, final OnClickListener listener) {}
public Builder setCancelable(boolean cancelable) {}
// ..................................................
public AlertDialog create() {} //创建dialog
public AlertDialog show() {} // 创建并显示真正的dialog
}
}
JAVA场景下:
public class User implements Serializable { // ... Member variable\Construction method\Setter\Getter /** * User 类建造者类 * @author test */ private static class UserBuild { /** * 用户编号 required 成员变量 */ private Integer id ; /** * 用户名称 required 成员变量 */ private String name ; /** * 用户年龄 optional 成员变量 */ private Integer age ; /** * 用户身高 optional 成员变量 */ private Integer height ; public UserBuild(Integer id ,String name){ this.id = id ; this.name = name ; } public UserBuild age(Integer age){ this.age = age ; return this ; } public UserBuild height(Integer height){ this.height = height ; return this ; } public User build(){ return new User(this); } } public static void main(String[] args) { User user = new UserBuild(1,"2").age(3).height(4).build(); System.out.println(user.toString()); System.out.println(user.getId()); System.out.println(user.getName()); System.out.println(user.getAge()); System.out.println(user.getHeight()); } }
把请求封装成对象,可以在使用不同的请求把客户端参数化。对于请求排队或者记录请求入职提供命令的取消和恢复。这是高内聚。
比如餐厅单点,直接将需求封装成命令对象再交给厨师
文件格式
command/
|-- cmd
| |-- Command.java // 命令抽象类 - 在这里是战术
| |-- InsideCommand.java // 打内线
| `-- ThreePointCommand.java // 三分战术
|-- Coach.java // 教练
|-- player
| |-- Center.java // 中锋
| |-- Player.java // 运动员抽象类
| |-- PointGuard.java // 控卫
| `-- SmallForward.java // 小前锋
`-- TestMain.java // 测试代码
以篮球训练为例作为示例代码
// 抽象命令 public abstract class Command { // 可以调用的人员 protected Center center = new Center(); protected PointGuard pontiGurad = new PointForward(); protected SmallForward smallForward = new SmallForward(); public abstract void execute(); } // 运动员抽象类 public abstract class Playter { public abstract void run(); public abstract void shoot(); public abstract void passBall(); public abstract void catchBall(); public abstract void dunk(); } // 教练类 public class Coach { private Command command; public void setCommand(Command command){ this.command = command; } public void action(){ this.command.execute(); } } // 各个人员类 public class Center extends Player { @Override public void run() { System.out.println("Center is running."); } @Override public void shoot() { System.out.println("Center shoots the ball"); } // ... 其它命令 } public class PointGuard extends Player { @Override public void run() { System.out.println("PointGuard is running."); } // ...与Center类似 } public class SmallForward extends Player { @Override public void run() { System.out.println("SmallForward is running."); } // ...与Center类似 } // 以下是简单两个命令 public class InsideCommand extends Command { public InsideCommand() { } @Override public void execute() { System.out.println(getClass().getSimpleName() + ":"); super.pointGurad.catchBall(); super.smallForward.run(); // ... } } public class ThreePointCommand extends Command { // ...与InsideCommand类似 } // 使用方式 Coach coach = new Coach(); Command command1 = new InsideCommand(); Command command2 = new ThreePointCommand(); coach.setCommand(command1); coach.action();
动态的给对象添加一些额外的职责。装饰模式比生成子类更加灵活,在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。
必须有一个接口或抽象类充当Componet抽象构建
文件结构
Component // 最基本的抽象构件,接口或抽象类
Operation()
ConcreteComponent // 具体的构件
Decorator // 抽象的装饰者
ConcreteComponent // 具体的装饰者
AWorker作为装饰者,Plumber成为被装饰者。
puiblic class Decoration { public static void main(String args[]) { Plumber plumber = new Plumber(); AWorker aWorker = new AWorker(plumber); aWorker.doSomeWork(); // BWorker同理 } } // Worker接口 interface Worker { void doSomeWork(); } class Plumber implements Worker { public void doSomeWork () { System.out.println("Plumber do some work!"); } } class Carpenter implements Worker { // 与Plumber同理 } class AWorker implements Worker { private Worker tempWorker; public AWorker(Worker worker) { tempWorker = worker; } public void doSomeWork() { System.out.println("Hello, I am a AWorker"); tempWorker.doSomeWork(); } } class BWorker implements Worker { private Worker worker; public BWorker(Worker worker) { this.worker = worker; } public void doSomeWork() { System.out.println("Hello, I am a BWorker");\ worker.doSomeWork(); } }
可以定义一种算法,并把每个算法都封装起来,可以互相替换
扩展性好,可以避免多重条件判断
每个策略都是一个类,复用率小
策略类需要对外暴露
场景
示例
文件结构
strategy/
|-- Add.java // 具体的策略
|-- Division.java // 具体的策略
|-- IStrategy.java // 策略接口
|-- Minus.java // 具体的策略
|-- Paper.java // 测试代码
`-- StrategyContext.java// 上下文角色,承上启下
具体代码
// 策略方法类 public interface IStrategy { float compute(float a, float b); } // 上下文类,用于屏蔽上层模块对策略的直接访问 public class StrategyContext { private IStrategy strategy; public void setStrategy(IStrategy strategy) { this.strategy = startegy; } public StrategyContext(IStrategy strategy) { this.strategy = strategy; } public float calculate(float a, float b) { return this.strategy.compute(a, b); } } // 具体的策略类 public class Add implements IStrategy { @Override public float compute(float a, float b) { return a + b; } } public class Minus implements IStrategy { // 与Add同理 } public class Division implements IStrategy { // 与Add同理 } // 使用方式 public static void main (String args[]) { StrategyContext context = new StrategyContext(new Add()); System.out.println("Add Res = " + context.caculate(1,3)); context.setStrategy(new Minus()); System.out.println("Minus Res = " + context.caculate(1,3)); // Division同理 }
也可以用枚举类来封装策略
public enum Calculator { ADD("+") { public float exec(float a, float b) { return a + b; } }, SUB("-") { public float exec(float a, float b) { return a - b; } } String value; Calculator(String _value) { this.value = _value; } public String getValue() { return value; } public abstract float exec(float a, float b); } // 使用方式 public static void main (String args[]) { System.out.println("ENUM ADD Res = " + Calculator.ADD.exec(12, 5)); System.out.println("ENUM SUB Res = " + Calculator.SUB.exec(2,5)); }
可以首先定义一个用于创建对象的接口。
具体要实例化什么的类区别于客户代码调用哪一类的工厂方法
所有需要生成对象的地方都可以受用,但是要慎重考虑是否需要一个工厂类来管理。
iterator()方法就是工厂方法模式的很好例子。
// Iterator接口: public interface Iterator<E> { boolean hasNext(); E next(); default void remove() { throw new UnsupportOperationException("remove"); } default void forEachRemaining(Consumer<? super E> action) { Objects.requireNonNull(action); while(hasNext()) action.accept(next()); } } // ArrayList中的iterator()方法返回一个ltr对象 public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{ public Iterator<E> iterator() { return new Itr(); } private class Itr implements Iterator<E> { // ... } } // LinkedList的iterator()返回的是另一种对象 // LinkerList<E> <-- AbstractSequentialList<E> <-- AbstractList<E> public ListIterator<E> listIterator() { return listIterator(0); } public ListIterator<E> listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index); } private class ListItr extends Itr implements ListIterator<E> { // ...... } private class Itr implements Iterator<E> { // ...... }
---- 后续待更新…
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。