设计模式类图在此链接
//www.greatytc.com/p/4fe3bb697a8f
“接口隔离”模式:
在组件构建过程中,某些接口之间直接的依赖常常会带来很多问题,甚至根本无法实现。采用添加一层间接(稳定)接口,来隔离本来互相紧密关联的接口是一种常见的解决方案。
典型模式
Facade(外观模式)
Proxy(代理模式)
Adapter(适配器模式)
Meditor(中介者模式)
Facade(外观模式)
动机(Motivation)
在一个大型代码外部增加新的特性,会导致新代码和旧代码中的子系统产生过多耦合,抵御变化能力降低。
如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统的变化之间的依赖相互解耦?
模式定义
为子系统中的一组接口提供一个一直(稳定)的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用(复用)。
——《设计模式》
要点总结
- 从客户程序的角度来看,Facade模式简化了整个组件系统的接口,对于组件内部与外部客户程序来说,达到了一种“解耦”的效果——内部子系统的任何变化不会影响到Facade接口的变化。
- Facade设计模式更注重从框架的层次去看整个系统,而不是单个类的层次。Facade很多时候更是一种架构设计模式。
- Facade设计模式并非一个集装箱,可以任意地放进任何多个对象。Facade模式中组件的内部应该是“相互耦合关系比较大的一系列组件”,而不是一个简单的功能集合。
Strategy 策略模式
动机(Motivation)
在软件构建过程中,某些对象使用的算法可能多种多样,经常改变,如果将这些算法都编码到对象中,将会使对象变得异常复杂;而且有时候支持不使用的算法也是一个性能负担。
如何在运行时根据需要透密地更新对象的算法?将算法与对象本身解耦,从而避免上述问题?
模式定义
定义一系列算法,把它们一个个封装起来,并且使它们可互相替换(变化)。该模式使得算法可以独立于使用它的客户程序(稳定)而变化(扩展,子类化)。
——《设计模式》
abstract class TaxStrategy {
abstract double Calculate(Context context);
}
class CNTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class USTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class DETax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
class FRTax extends TaxStrategy {
@Override
double Calculate(Context context) {
return 0;
}
}
public class SaleOrder {
TaxStrategy taxStrategy;
public SaleOrder(TaxStrategy taxStrategy) {
this.taxStrategy = taxStrategy;
}
public double CalculateTax() {
Context context = null;
double val = taxStrategy.Calculate(context);
return val;
}
}
要点总结
- Strategy及其子类为组件提供了一系列可重用的算法,从而使得类型在运行时方便地根据需要在各个算法之间进行切换。
- Strategy模式提供了用条件判断语句以外的另一种选择,消除条件判断语句,就是在解耦合。含有许多条件判断语句的代码通常都需要Strategy模式。
- 如果Strategy对象没有实例变量,那么各个上下文可以共享同一个Strategy对象,从而节省对象开销。
Observer观察者模式
动机(Motivation)
在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有的依赖对象(观察者对象)都将得到通知。如果这样的依赖关系过于紧密,将使软件不能很好地抵御变化。
使用面向对象技术,可以将这种依赖关系弱化,并形成一种稳定的依赖关系。从而实现软件体系结构的松耦合。
模式定义
定义对象间的一种一对多(变化)的依赖关系,以便当一个对象(Subject)的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。
——《设计模式》
public class MainActivity extends AppCompatActivity {
private Button mAppendButton;
private EditText mEditText;
private TextView mLabelText;
private int count=0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAppendButton = (Button) findViewById(R.id.appendButton);
mEditText = (EditText) findViewById(R.id.contentEdit);
mLabelText = (TextView) findViewById(R.id.countText);
//订阅通知
mEditText.addTextChangedListener(textWatcher);
//取消订阅
//mEditText.removeTextChangedListener(textWatcher);
mAppendButton.setOnClickListener(clickListener);
}
OnClickListener clickListener = new OnClickListener() {
@Override
public void onClick(View v) {
String content = mEditText.getText().toString().trim();
//文本框内容处理
content = content + Integer.toString(count);
count++;
mEditText.setText(content);
mEditText.setSelection(content.length());//光标置于末尾
}
};
TextWatcher textWatcher = new TextWatcher() {
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.i("BeforeTextChanged:", s.toString() );
}
public void onTextChanged(CharSequence s, int start, int before, int count) {
Log.i("OnTextChanged:", s.toString() );
}
public void afterTextChanged(Editable s) {
String count = Integer.toString(s.length());
mLabelText.setText(count);
}
};
}
要点总结
- 增加的Listener会组成一个ArrayList,每当目标对象状态发生改变,则遍历ArrayList通知所有观察者。
- 使用面向对象的抽象,Observer模式使我们可以独立地改变目标与观察者,从而使二者之间的依赖关系达致松耦合。
- 目标发送通知时,无需指定观察者,通知(可以携带通知信息作为参数)会自动传播。
- 观察者自己决定是否需要订阅通知,目标对象对此一无所知。
- Observer模式是基于事件的UI框架中非常常用的设计模式,也是MVC模式的一个重要组成部分。
“单一职责”模式:
Decorator(装饰模式)
Bridge(桥接模式)
Decorator(装饰模式)
动机(Motivation)
在某些情况下我们可能会“过度地使用继承来扩展对象的功能”由于继承为类型引入的静态特质,使得这种扩展方法缺乏灵活性;并且随着子类的增多(扩展功能的增多),各种子类的组合(扩展功能的组合)会导致更多子类的膨胀。
如何使“对象功能的扩展”能够根据需要来动态地实现?同时避免“扩展功能的增多”带来的子类膨胀问题?从而使得任何“功能扩展变化”所导致的影响将为最低?
一种较为灵活的方式是将组件嵌入另一个对象中,由这个对象添加功能。我们称这个嵌入的对象为装饰。这个装饰与它所装饰的组件接口一致,因此它对使用该组件的客户透明。它将客户请求转发给该组件,并且可能在转发前后执行一些额外的动作。透明性使得你可以递归的嵌套多个装饰,从而可以添加任意多的功能。
模式定义
动态(组合)地给一个对象增加一些额外的职责。就增加功能而言,Decorator模式比生成子类(继承)更多灵活(消除重复代码&减少子类个数)。
——《设计模式》
abstract class Stream {
public abstract char read(int number);
public abstract void seek(int position);
public abstract void write(char data);
}
//主体类
class FileStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
class NetworkStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
class MemoryStream extends Stream {
@Override
public char read(int number) {
return 0;
}
@Override
public void seek(int position) {
}
@Override
public void write(char data) {
}
}
//继承:接口协议
abstract class DecroratorStream extends Stream {
protected Stream s;
protected DecroratorStream(Stream s) { //可以传递Stream的子类,根据不同的主体,进行不同的活动
this.s = s;
}
}
class CroptoStream extends DecroratorStream {
//通过调用父类,实例化s
public CroptoStream(Stream s) {
super(s);
}
@Override
public char read(int number) {
s.read(number);
return 0;
}
@Override
public void seek(int position) {
s.seek(position);
}
@Override
public void write(char data) {
s.write(data);
}
}
class BufferedStream extends DecroratorStream{
//通过调用父类,实例化s
public BufferedStream(Stream s) {
super(s);
}
@Override
public char read(int number) {
s.read(number);
return 0;
}
@Override
public void seek(int position) {
s.seek(position);
}
@Override
public void write(char data) {
s.write(data);
}
}
class Client{
public static void main(String[] args) {
FileStream fileStream = new FileStream();
Stream s1 = new CroptoStream(fileStream);
Stream s2 = new BufferedStream(new MemoryStream());
Stream s3 = new CroptoStream(new BufferedStream(new NetworkStream()));
}
}
要点总结
- 通过采用组合而非继承的手法,Decorator模式实现了在运行时动态扩展对象功能的能力,而且可以根据需要扩展多个功能。避免了使用继承带来的“灵活性差”和“多子类衍生问题”。
- Decorator类在接口是表现为is-a Component的继承关系,即Decorator类继承了Component类所具有的接口。但在实现上又表现为has-a Component的组合关系,即Decorator类又使用了另一个Component类。
- Decorator模式的目的并非解决“多子类衍生的多继承”问题,Decorator模式应用的要点在于解决“主体类在多个方向上的扩展功能”——是为“装饰”的含义。
Bridge (桥接模式)
动机(Motivation)
- 由于某些类型的固有的实现逻辑,使得它们具有两个变化的维度,乃至多个维度的变化。
- 如何应对这种“多维度的变化”?如何利用面向对象技术来使得类型可以轻松地沿着两个乃至多个方向变化,而不引入额外的复杂度?
模式定义
将抽象部分(业务功能)与实现部分(平台实现)分离,使它们都可以独立地变化。
——《设计模式》
abstract class Messager {
MessageImp msgImp; //实现了MessageImp子类的功能
protected Messager(MessageImp msgImp) {
this.msgImp = msgImp;
}
public abstract void login(String username, String password);
public abstract void sendMessage(String message);
public abstract void sendPicture(Image image);
}
abstract class MessageImp{
public abstract void playSound();
public abstract void drawShape();
public abstract void writeText();
public abstract void connect();
}
//平台实现
class PCMessageImp extends MessageImp{
@Override
public void playSound() {
}
@Override
public void drawShape() {
}
@Override
public void writeText() {
}
@Override
public void connect() {
}
}
class MobileMessageImp extends MessageImp{
@Override
public void playSound() {
}
@Override
public void drawShape() {
}
@Override
public void writeText() {
}
@Override
public void connect() {
}
}
//业务抽象
class MessagerLite extends Messager{
protected MessagerLite(MessageImp msgImp) {
super(msgImp);
}
@Override
public void login(String username, String password) {
msgImp.connect();
}
@Override
public void sendMessage(String message) {
msgImp.writeText();
}
@Override
public void sendPicture(Image image) {
msgImp.drawShape();
}
}
class MessagerPerfect extends Messager{
protected MessagerPerfect(MessageImp msgImp) {
super(msgImp);
}
@Override
public void login(String username, String password) {
msgImp.playSound();
msgImp.connect();
}
@Override
public void sendMessage(String message) {
msgImp.playSound();
msgImp.writeText();
}
@Override
public void sendPicture(Image image) {
msgImp.playSound();
msgImp.drawShape();
}
}
要点总结
- Bridge模式使用“对象间的组合关系”解耦了抽象和实现之间固有的绑定关系,使得抽象和实现可以沿着各自的维度来变化。所谓抽象和实现沿着各自维度的变化,即“子类化”它们。
- Bridge模式有时候类似于多继承方案,但是多继承方案往往违背单一职责原则(即一个类只有一个变化的原因),复用性比较差。Bridge模式是比多继承方案更好的解决方法。
- Bridge模式的应用一般在“两个非常强的变化维度”,有时一个类也有多于两个的变化维度,这时可以使用Bridge的扩展模式。
"对象创建“模式:
典型模式
Factory Method(工厂方法)
Abstract Factory(抽象工厂模式)
Prototype(原型模式)
Builder(生成器)
6.Factory Method模式 Factory method模式用于隔离类对象的使用者和具体类型之间的耦合关系。面对一个经常变化的具体类型,紧耦合关系会导致软件的脆弱。 Factory Method模式通过面对对象的手法,将所要创建的具体对象工作延迟到子类,从而实现一种扩展的策略,较好地解决了这种紧耦合关系。 Factory Method模式解决“单个对象”的需求变化,缺点在于要求创建方法/参数相同。
7.Abstract Factory工厂 该模式主要在于应对“新系列”的需求变动。其缺点在于难以应对“新对象”的需求变动。 如果没有应对“多系列对象构建”的需求变化,则没有必须使用这个模式,这时候使用简单工厂完全可以。
由于设计模式很多,而且设计模式在初学阶段一般不做要求,所以对于初学者大家可以不用掌握,但要在设计中逐渐去体会它。