心里一直想学好用好设计模式,这次以博客记录的方式一个一个的去学习记录并分享一下。
辅助博客:http://c.biancheng.net/view/1317.html
https://www.runoob.com/design-pattern/singleton-pattern.html
设计模式的本质是面向对象设计原则的实际运用,是对类的封装性、继承性和多态性以及类的关联关系和组合关系的充分理解。正确使用设计模式具有以下优点。
- 可以提高程序员的思维能力、编程能力和设计能力。
- 使程序设计更加标准化、代码编制更加工程化,使软件开发效率大大提高,从而缩短软件的开发周期。
- 使设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。
一 设计原则
1,单一职责原则:最小粒度可以是类也可以是方法
2,里氏替换原则:任何基类可以出现的地方,子类一定可以替换,范围只能缩小不能扩大(多态)
3,开闭原则:对扩展开放,对修改关闭
4,迪米特法则:不需要让别人知道的都不要告诉别人
5,依赖倒置原则:依赖接口,从上层抽象(高层业务)
6,接口隔离原则:建立单一接口
二 设计模式
设计模式有两种分类方法,即根据模式的目的来分和根据模式的作用的范围来分。
1. 根据目的来分
根据模式是用来完成什么工作来划分,这种方式可分为创建型模式、结构型模式和行为型模式 3 种。
- 创建型模式:用于描述“怎样创建对象”,它的主要特点是“将对象的创建与使用分离”。GoF 中提供了单例、原型、工厂方法、抽象工厂、建造者等 5 种创建型模式。
- 结构型模式:用于描述如何将类或对象按某种布局组成更大的结构,GoF 中提供了代理、适配器、桥接、装饰、外观、享元、组合等 7 种结构型模式。
- 行为型模式:用于描述类或对象之间怎样相互协作共同完成单个对象都无法单独完成的任务,以及怎样分配职责。GoF 中提供了模板方法、策略、命令、职责链、状态、观察者、中介者、迭代器、访问者、备忘录、解释器等 11 种行为型模式。
2. 根据作用范围来分
根据模式是主要用于类上还是主要用于对象上来分,这种方式可分为类模式和对象模式两种。
- 类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。GoF中的工厂方法、(类)适配器、模板方法、解释器属于该模式。
- 对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式。
3. GoF的23种设计模式的功能
前面说明了 GoF 的 23 种设计模式的分类,现在对各个模式的功能进行介绍。
- 单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。
- 原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例。
- 工厂方法(Factory Method)模式:定义一个用于创建产品的接口,由子类决定生产什么产品。
- 抽象工厂(AbstractFactory)模式:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
- 建造者(Builder)模式:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象。
- 代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
- 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
- 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。
- 装饰(Decorator)模式:动态的给对象增加一些职责,即增加其额外的功能。
- 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
- 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
- 组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。
- 模板方法(TemplateMethod)模式:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
- 策略(Strategy)模式:定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的改变不会影响使用算法的客户。
- 命令(Command)模式:将一个请求封装为一个对象,使发出请求的责任和执行请求的责任分割开。
- 职责链(Chain of Responsibility)模式:把请求从链中的一个对象传到下一个对象,直到请求被响应为止。通过这种方式去除对象之间的耦合。
- 状态(State)模式:允许一个对象在其内部状态发生改变时改变其行为能力。
- 观察者(Observer)模式:多个对象间存在一对多关系,当一个对象发生改变时,把这种改变通知给其他多个对象,从而影响其他对象的行为。
- 中介者(Mediator)模式:定义一个中介对象来简化原有对象之间的交互关系,降低系统中对象间的耦合度,使原有对象之间不必相互了解。
- 迭代器(Iterator)模式:提供一种方法来顺序访问聚合对象中的一系列数据,而不暴露聚合对象的内部表示。
- 访问者(Visitor)模式:在不改变集合元素的前提下,为一个集合中的每个元素提供多种访问方式,即每个元素有多个访问者对象访问。
- 备忘录(Memento)模式:在不破坏封装性的前提下,获取并保存一个对象的内部状态,以便以后恢复它。
- 解释器(Interpreter)模式:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
三 创建型模式
1,单例模式
1)定义:指一个类只有一个实例,且该类能自行创建这个实例的一种模式。
2) 特点:
- 单例类只有一个实例对象;
- 该单例对象必须由单例类自行创建;
- 单例类对外提供一个访问该单例的全局访问点。
3) 优缺点:
优点:
缺点:
- 单例模式可以保证内存里只有一个实例,减少了内存的开销。
- 可以避免对资源的多重占用。
- 单例模式设置全局访问点,可以优化和共享资源的访问。
- 单例模式一般没有接口,扩展困难。如果要扩展,则除了修改原来的代码,没有第二种途径,违背开闭原则。
- 在并发测试中,单例模式不利于代码调试。在调试过程中,如果单例中的代码没有执行完,也不能模拟生成一个新的对象。
- 单例模式的功能代码通常写在一个类中,如果功能设计不合理,则很容易违背单一职责原则。
4) 应用场景:
对于 Java 来说,单例模式可以保证在一个 JVM 中只存在单一实例。单例模式的应用场景主要有以下几个方面。
- 需要频繁创建的一些类,使用单例可以降低系统的内存压力,减少 GC。
- 某类只要求生成一个对象的时候,如一个班中的班长、每个人的身份证号等。
- 某些类创建实例时占用资源较多,或实例化耗时较长,且经常使用。
- 某类需要频繁实例化,而创建的对象又频繁被销毁的时候,如多线程的线程池、网络连接池等。
- 频繁访问数据库或文件的对象。
- 对于一些控制硬件级别的操作,或者从系统上来讲应当是单一控制逻辑的操作,如果有多个实例,则系统会完全乱套。
- 当对象需要被共享的场合。由于单例模式只允许创建一个对象,共享该对象可以节省内存,并加快对象访问速度。如 Web 中的配置对象、数据库的连接池等。
5)demo只有双重检查锁(部分代码)
private static volatile MusicOperation sMusicOperation; private MusicOperation(Context context) { ... } public static MusicOperation getInstance(Context context) { if (sMusicOperation == null) { synchronized (MusicOperation.class) { if (sMusicOperation == null) { sMusicOperation = new MusicOperation(context.getApplicationContext()); } } } return sMusicOperation; }
2,简单工厂、工厂方法、抽象工厂模式
2.1 简单工厂
1)定义:定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。
2)优缺点:
优点:
- 工厂类包含必要的逻辑判断,可以决定在什么时候创建哪一个产品的实例。客户端可以免除直接创建产品对象的职责,很方便的创建出相应的产品。工厂和产品的职责区分明确。
- 客户端无需知道所创建具体产品的类名,只需知道参数即可。
- 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。
缺点:
- 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高聚合原则。
- 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度
- 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂
- 简单工厂模式使用了 static 工厂方法,造成工厂角色无法形成基于继承的等级结构。
3)应用场景:对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
4)demo
public class FragmentFactory { private static final String TAG = "FragmentFactory"; public static Fragment createFragment(int position) { Fragment fragment = null; switch (position){ case FragmentPageId.MINE_PAGE_ID: fragment = new MinePageFragment(); break; case FragmentPageId.MAIN_PAGE_ID: fragment = new MainPageFragment(); break; default: LogUtils.e(TAG, "null fragment created"); break; } return fragment; } }
2.2 工厂方法
1)定义:简单工厂模式违背了开闭原则,而“工厂方法模式”是对简单工厂模式的进一步抽象化,其好处是可以使系统在不修改原来代码的情况下引进新的产品,即满足开闭原则。
注意:当需要生成的产品不多且不会增加,一个具体工厂类就可以完成任务时,可删除抽象工厂类。这时工厂方法模式将退化到简单工厂模式。
2)优缺点
优点:
- 用户只需要知道具体工厂的名称就可得到所要的产品,无须知道产品的具体创建过程。
- 灵活性增强,对于新产品的创建,只需多写一个相应的工厂类。
- 典型的解耦框架。高层模块只需要知道产品的抽象类,无须关心其他实现类,满足迪米特法则、依赖倒置原则和里氏替换原则。
缺点:
- 类的个数容易过多,增加复杂度
- 增加了系统的抽象性和理解难度
- 抽象产品只能生产一种产品,此弊端可使用抽象工厂模式解决。
3)应用场景
- 客户只知道创建产品的工厂名,而不知道具体的产品名。如 TCL 电视工厂、海信电视工厂等。
- 创建对象的任务由多个具体子工厂中的某一个完成,而抽象工厂只提供创建产品的接口。
- 客户不关心创建产品的细节,只关心产品的品牌
4)demo
public interface AnimalFarm { Animal newAnimal(); }
public class HorseFarm implements AnimalFarm{ private static final String TAG = "HorseFarm"; @Override public Animal newAnimal() { Log.d(TAG, "newAnimal: horse"); return new Horse(); } }
public class SheepFarm implements AnimalFarm{ private static final String TAG = "SheepFarm"; @Override public Animal newAnimal() { Log.d(TAG, "newAnimal: sheep"); return new Sheep(); } }
public interface Animal { String show(); }
public class Horse implements Animal{ private static final String TAG = "Horse"; @Override public String show() { return "show: horse"; } }
public class Sheep implements Animal{ private static final String TAG = "Sheep"; @Override public String show() { return "show: sheep"; } }
public class ClientActivity extends AppCompatActivity { private Button mHorse; private Button mSheep; private TextView mMessage; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client); initView(); initListener(); } private void initView() { mHorse = findViewById(R.id.horse); mSheep = findViewById(R.id.sheep); mMessage = findViewById(R.id.message); } private void initListener() { mHorse.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AnimalFarm horseFarm = new HorseFarm(); Animal horse = horseFarm.newAnimal(); String show = horse.show(); mMessage.setText(show); } }); mSheep.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { AnimalFarm sheepFarm = new SheepFarm(); Animal sheep = sheepFarm.newAnimal(); String show = sheep.show(); mMessage.setText(show); } }); } }
2.3 抽象工厂
1)定义:是一种为访问类提供一个创建一组相关或相互依赖对象的接口,且访问类无须指定所要产品的具体类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。,下图所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
2)特点
使用抽象工厂模式一般要满足以下条件。
- 系统中有多个产品族,每个具体工厂创建同一族但属于不同等级结构的产品。
- 系统一次只可能消费其中某一族产品,即同族的产品一起使用。
3)优缺点
抽象工厂模式除了具有工厂方法模式的优点外,其他主要优点如下。
- 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来进行管理。
- 当需要产品族时,抽象工厂可以保证客户端始终只使用同一个产品的产品组。
- 抽象工厂增强了程序的可扩展性,当增加一个新的产品族时,不需要修改原代码,满足开闭原则。
其缺点是:当产品族中需要增加一个新的产品时,所有的工厂类都需要进行修改。增加了系统的抽象性和理解难度。4)demo
public interface Animal { String show(); } public interface Plant { String show(); } public interface Farm { Animal newAnimal(); Plant newPlant(); }
public class Horse implements Animal{ @Override public String show() { return "Horse show"; } } public class Sheep implements Animal{ @Override public String show() { return "Sheep show"; } } public class Fruit implements Plant{ @Override public String show() { return "Fruit show"; } } public class Vegetables implements Plant{ @Override public String show() { return "Vegetables show"; } } public class SRFarmFactory implements Farm{ @Override public Animal newAnimal() { return new Horse(); } @Override public Plant newPlant() { return new Fruit(); } } public class SGFarmFactory implements Farm{ @Override public Animal newAnimal() { return new Sheep(); } @Override public Plant newPlant() { return new Vegetables(); } }
public class ClientActivity extends AppCompatActivity { private TextView mText; private Button mSRBtn; private Button mSGBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client2); initView(); initListener(); } private void initView() { mText = findViewById(R.id.FarmText); mSRBtn = findViewById(R.id.SRBtn); mSGBtn = findViewById(R.id.SGBtn); } private void initListener() { mSRBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Farm srFarmFactory = new SRFarmFactory(); Animal animal = srFarmFactory.newAnimal(); Plant plant = srFarmFactory.newPlant(); String ani = animal.show(); String sh = plant.show(); String text = ani + "," + sh; mText.setText(text); } }); mSGBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Farm sgFarmFactory = new SGFarmFactory(); Animal animal = sgFarmFactory.newAnimal(); Plant plant = sgFarmFactory.newPlant(); String text = animal.show() + "," + plant.show(); mText.setText(text); } }); } }
3,状态模式
1)定义:对有状态的对象,把复杂的“判断逻辑”提取到不同的状态对象中,允许状态对象在其内部状态发生改变时改变其行为。
2)解决思想是:当控制一个对象状态转换的条件表达式过于复杂时,把相关“判断逻辑”提取出来,用各个不同的类进行表示,系统处于哪种情况,直接使用相应的状态类对象进行处理,这样能把原来复杂的逻辑判断简单化,消除了 if-else、switch-case 等冗余语句,代码更有层次性,并且具备良好的扩展力。
3)优缺点:
状态模式是一种对象行为型模式,其主要优点如下。
- 结构清晰,状态模式将与特定状态相关的行为局部化到一个状态中,并且将不同状态的行为分割开来,满足“单一职责原则”。
- 将状态转换显示化,减少对象间的相互依赖。将不同的状态引入独立的对象中会使得状态转换变得更加明确,且减少对象间的相互依赖。
- 状态类职责明确,有利于程序的扩展。通过定义新的子类很容易地增加新的状态和转换。
状态模式的主要缺点如下。
- 状态模式的使用必然会增加系统的类与对象的个数。
- 状态模式的结构与实现都较为复杂,如果使用不当会导致程序结构和代码的混乱。
- 状态模式对开闭原则的支持并不太好,对于可以切换状态的状态模式,增加新的状态类需要修改那些负责状态转换的源码,否则无法切换到新增状态,而且修改某个状态类的行为也需要修改对应类的源码。
4)demo,状态间的转换都是设定好的,不能随意切换。
public abstract class ThreadState { protected String mThreadState; public String getCurrentState() { return ""; } } /** * 新建状态 */ public class New extends ThreadState{ private static final String NEW_STATE = "新建状态"; public New() { mThreadState = NEW_STATE; } public String start(ThreadContext context) { String result = "调用start方法"; if (NEW_STATE.equals(mThreadState)) { context.setState(new Runnable()); } else { result = "当前状态不是新建状态,不能调用start方法"; } return result; } @Override public String getCurrentState() { return mThreadState; } } /** * 就绪状态 */ public class Runnable extends ThreadState{ private static final String RUNNABLE_STATE = "就绪状态"; public Runnable() { mThreadState = RUNNABLE_STATE; } public String getCPU(ThreadContext context) { String result = "调用getCPU方法"; if (RUNNABLE_STATE.equals(mThreadState)) { context.setState(new Running()); } else { result = "当前状态不是就绪状态,不能调用getCPU方法"; } return result; } @Override public String getCurrentState() { return mThreadState; } } /** * 运行状态 */ public class Running extends ThreadState{ private static final String RUNNING = "运行状态"; public Running() { mThreadState = RUNNING; } /** * 阻塞 * @param context * @return */ public String suspend(ThreadContext context) { String result = "调用suspend方法"; if (RUNNING.equals(mThreadState)) { context.setState(new Blocked()); } else { result = "当前状态不是运行状态,不能调用suspend方法"; } return result; } /** * 杀死 * @param context * @return */ public String dead(ThreadContext context) { String result = "调用dead方法"; if (RUNNING.equals(mThreadState)) { context.setState(new Dead()); } else { result = "当前状态不是运行状态,不能调用dead方法"; } return result; } @Override public String getCurrentState() { return mThreadState; } } /** * 阻塞状态 */ public class Blocked extends ThreadState{ private static final String BLOCK_STATE = "阻塞状态"; public Blocked() { mThreadState = BLOCK_STATE; } public String resume(ThreadContext context) { String result = "调用resume方法"; if (BLOCK_STATE.equals(mThreadState)) { context.setState(new Runnable()); } else { result = "当前状态不是阻塞状态,不能调用resume方法"; } return result; } @Override public String getCurrentState() { return mThreadState; } } /** * 死亡状态 */ public class Dead extends ThreadState{ private static final String DEAD_STATE = "死亡状态"; public Dead() { mThreadState = DEAD_STATE; } @Override public String getCurrentState() { return mThreadState; } }
/** * 环境类 */ public class ThreadContext { private ThreadState state; /** * 默认新建状态 */ public ThreadContext() { state = new New(); } public ThreadState getState() { return state; } public void setState(ThreadState state) { this.state = state; } /** * 启动线程 * @return */ public String start() { return ((New)state).start(this); } /** * 获取CPU * @return */ public String getCPU() { return ((Runnable)state).getCPU(this); } /** * 阻塞 * @return */ public String block() { return ((Running)state).suspend(this); } /** * 阻塞恢复运行 * @return */ public String resume() { return ((Blocked)state).resume(this); } /** * 死亡 * @return */ public String dead() { return ((Running)state).dead(this); } /** * 当前所处状态 * @return */ public String getCurrentState() { return state.getCurrentState(); } }
public class ClientActivity extends AppCompatActivity { private TextView mText; private Button mStart; private Button mRunnable; private Button mRunning; private Button mBlock; private Button mDead; private ThreadContext mThreadContext; private String mCurrentState; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_client3); initView(); initListener(); } private void initView() { mText = findViewById(R.id.thread_text); mStart = findViewById(R.id.new_btn); mRunnable = findViewById(R.id.runnable); mRunning = findViewById(R.id.running); mBlock = findViewById(R.id.block); mDead = findViewById(R.id.dead); } private void initListener() { mThreadContext = new ThreadContext(); mCurrentState = mThreadContext.getCurrentState(); mText.setText(mCurrentState); mStart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String start = mThreadContext.start(); mCurrentState = mThreadContext.getCurrentState(); String text = start + "\n当前状态:" + mCurrentState; mText.setText(text); } }); mRunnable.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String cpu = mThreadContext.getCPU(); mCurrentState = mThreadContext.getCurrentState(); String text = cpu + "\n当前状态:" + mCurrentState; mText.setText(text); } }); mRunning.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String block = mThreadContext.block(); mCurrentState = mThreadContext.getCurrentState(); String text = block + "\n当前状态:" + mCurrentState; mText.setText(text); } }); mBlock.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String resume = mThreadContext.resume(); mCurrentState = mThreadContext.getCurrentState(); String text = resume + "\n当前状态:" + mCurrentState; mText.setText(text); } }); mDead.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String dead = mThreadContext.dead(); mCurrentState = mThreadContext.getCurrentState(); String text = dead + "\n当前状态:" + mCurrentState; mText.setText(text); } }); }
4,策略模式
1)定义:该模式定义了一系列算法,并将每个算法封装起来,使它们可以相互替换,且算法的变化不会影响使用算法的客户。策略模式属于对象行为模式,它通过对算法进行封装,把使用算法的责任和算法的实现分割开来,并委派给不同的对象对这些算法进行管理。
2)关键点:实现同一个接口,将这些算法封装成一个一个的类,任意地替换。
3)优缺点:
优点如下。
- 多重条件语句不易维护,而使用策略模式可以避免使用多重条件语句,如 if...else 语句、switch...case 语句。
- 策略模式提供了一系列的可供重用的算法族,恰当使用继承可以把算法族的公共代码转移到父类里面,从而避免重复的代码。
- 策略模式可以提供相同行为的不同实现,客户可以根据不同时间或空间要求选择不同的。
- 策略模式提供了对开闭原则的完美支持,可以在不修改原代码的情况下,灵活增加新算法。
- 策略模式把算法的使用放到环境类中,而算法的实现移到具体策略类中,实现了二者的分离。
其主要缺点如下。
- 客户端必须理解所有策略算法的区别,以便适时选择恰当的算法类。
- 策略模式造成很多的策略类,增加维护难度。
4)demo,与状态模式不同,状态模式是设定好的可以自动转换,而策略模式是可以自己组装的。
public interface CrabCooking { String CookingMethod(); }
/** * 清蒸 */ public class SteamedCrab implements CrabCooking{ @Override public String CookingMethod() { String result = "Let's steamed this crab!"; return result; } } /** * 红烧 */ public class BraisedCrabs implements CrabCooking{ @Override public String CookingMethod() { String result = "Let's braised this crab!"; return result; } } public class Kitchen { private CrabCooking mCrabCooking; public CrabCooking getCrabCooking() { return mCrabCooking; } public void setCrabCooking(CrabCooking crabCooking) { this.mCrabCooking = crabCooking; } public String CookingMethod() { return mCrabCooking.CookingMethod(); } }
private void initListener() { mKitchen = new Kitchen(); mSteamed.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mKitchen.setCrabCooking(new SteamedCrab()); String result = mKitchen.CookingMethod(); mText.setText(result); } }); mBraised.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mKitchen.setCrabCooking(new BraisedCrabs()); String result = mKitchen.CookingMethod(); mText.setText(result); } }); }
5,建造者模式
1)定义:指将一个复杂对象的构造与它的表示分离,使同样的构建过程可以创建不同的表示,这样的设计模式被称为建造者模式。它是将一个复杂的对象分解为多个简单的对象,然后一步一步构建而成。它将变与不变相分离,即产品的组成部分是不变的,但每一部分是可以灵活选择的。
2)优缺点:
该模式的主要优点如下:
- 封装性好,构建和表示分离。
- 扩展性好,各个具体的建造者相互独立,有利于系统的解耦。
- 客户端不必知道产品内部组成的细节,建造者可以对创建过程逐步细化,而不对其它模块产生任何影响,便于控制细节风险。
其缺点如下:
- 产品的组成部分必须相同,这限制了其使用范围。
- 如果产品的内部变化复杂,如果产品内部发生变化,则建造者也要同步修改,后期维护成本较大。
3)demo:建造者(Builder)模式和工厂模式的关注点不同:建造者模式注重零部件的组装过程,而工厂方法模式更注重零部件的创建过程,但两者可以结合使用。
package designpattern.builder; /** * 产品 */ public class Product { private String partA; private String partB; private String partC; public void setPartA(String partA) { this.partA = partA; } public void setPartB(String partB) { this.partB = partB; } public void setPartC(String partC) { this.partC = partC; } public String show() { return partA + "," + partB + "," + partC; } }
package designpattern.builder; /** * 抽象建造者 */ abstract class Builder { protected Product product = new Product(); public abstract void buildPartA(); public abstract void buildPartB(); public abstract void buildPartC(); public Product getResult() { return product; } }
package designpattern.builder; /** * 第一个建造者 */ public class FirstConcreteBuilder extends Builder { @Override public void buildPartA() { product.setPartA("build first partA"); } @Override public void buildPartB() { product.setPartB("build first partB"); } @Override public void buildPartC() { product.setPartC("build first partC"); } }
package designpattern.builder; /** * 第二个建造者 */ public class SecondConcreteBuilder extends Builder { @Override public void buildPartA() { product.setPartA("build second partA"); } @Override public void buildPartB() { product.setPartB("build second partB"); } @Override public void buildPartC() { product.setPartC("build second partC"); } }
package designpattern.builder; /** * 指挥者 */ public class Director { private Builder builder; public Director(Builder builder) { this.builder = builder; } public Product construct() { builder.buildPartA(); builder.buildPartB(); builder.buildPartC(); return builder.getResult(); } }
package designpattern.builder; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView; import com.example.androidpratic.R; public class BuilderActivity extends AppCompatActivity { private TextView mTextView; private Button mFirst; private Button mSecond; private Director director; private Builder builder; private Product product; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_builder); initView(); initListener(); } private void initView() { mTextView = findViewById(R.id.text_builder); mFirst = findViewById(R.id.first_builder); mSecond = findViewById(R.id.second_builder); } private void initListener() { mFirst.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { builder = new FirstConcreteBuilder(); director = new Director(builder); product = director.construct(); mTextView.setText(product.show()); } }); mSecond.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { builder = new SecondConcreteBuilder(); director = new Director(builder); product = director.construct(); mTextView.setText(product.show()); } }); } }