|
模式是在特定环境下人们解决某类重复出现问题的一套成功或有效的解决方案
在软件开发生命周期的每一个阶段都存在着一些被认同的模式
什么是设计模式
设计模式(Design Pattern)是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结,使用设计模式是为了可重用代码、让代码更容易被他人理解并且保证代码可靠性。
设计模式一般包含模式名称、问题、目的、解决方案、效果等组成要素,其中关键要素是模式名称、问题、解决方案和效果
设计模式分为三类: 5种创建型模式 、 7种结构型模式 、 11种行为型模式
23种设计模式
创建型模式:单例模式、抽象工厂模式、建造者模式、工厂模式、原型模式。
结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
行为型模式:模版方法模式、命令模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式、状态模式、策略模式、职责链模式(责任链模式)、访问者模式。
复习的时候,发现了一个很有趣的开源代码: https://github.com/youlookwhat/DesignPattern
设计模式的六大原则
1.开闭原则:对扩展开放,对修改关闭;
2.里氏替换原则:任何基类可以出现的地方,子类一定可以出现
LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为
依赖倒转原则:开闭原则的基础;针对接口变成,依赖于抽象而不依赖于具体;
接口隔离原则:使用多个隔离的接口,比使用单个接口要好
最少知道原则:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立(高内聚低耦合)
合成复用原则:尽量使用合成/聚合的方式,而不是使用继承
创建型模式
单例模式
单例模式,保证JVM中只有一个单例对象并且该对象只有一个实例存在;
好处:
1、某些类创建比较频繁,对于一些大型的对象,这是一笔很大的系统开销
2、省去了new操作符,降低了系统内存的使用频率,减轻GC压力
3、有些类如交易所的核心交易引擎,控制着交易流程,如果该类可以创建多个的话,系统完全乱了。(比如一个军队出现了多个司令员同时指挥,肯定会乱成一团),所以只有使用单例模式,才能保证核心交易服务器独立控制整个流程。
坏处:之前看过内存溢出相关的文章,单例模式的滥用似乎很容易发生内存溢出;
eg:(栗子来自于: http://blog.csdn.net/zhangerqing/article/details/8194653 )
public class Singleton{
private static Singleton instance = null;
//私有构造方法,防止被实例化
private Singleton(){}
//synchronized 用作线程保护
public staticSingletongetInstance(){
synchronized (instance) {
if (instance == null) {
instance = new Singleton();
}
}
return instance;
}
//如果对象被用于序列化,可以保证对象在序列化前后保持一致;
publicObjectreadResolce(){
return instance;
}
}
/*优化:*/
private static class SingletonFactory{
private static Singleton instance = new Singleton();
}
public staticSingletongetInstance(){
return SingletonFactory.instance;
}
}
可以利用内部类来维护单例的实现:
public class Singleton{
/* 私有构造方法,防止被实例化 */
private Singleton(){
}
/* 此处使用一个内部类来维护单例 */
private static class SingletonFactory{
private static Singleton instance = new Singleton();
}
/* 获取实例 */
public staticSingletongetInstance(){
return SingletonFactory.instance;
}
/* 如果该对象被用于序列化,可以保证对象在序列化前后保持一致 */
publicObjectreadResolve(){
return getInstance();
}
}
工厂模式
工厂模式分为:普通工厂模式,多个工厂模式,静态工厂模式
普通工厂模式
建立一个工厂类,对实现了同一接口的一些类进行实例的创建
eg:来自: http://blog.csdn.net/zhangerqing/article/details/8194653
public interface Sender{
public void Send();
}
//Class_1
public class MailSender implements Sender{
@Override
public void Send(){
...
}
}
//Class_2
public class SmsSender implements Sender{
@Override
public void Send(){
...
}
}
/ **
/ * Factory:
** /
public class SendFactory{
public Sender produce(String type){
if("mail".equals(type)){
return new MailSender();
}else if("sms".equals(type)){
retrun new SmsSender();
}else{
...
return null;
}
}
}
//Test
public class FactoryTest{
public static void main(String[] args){
SendFactory factory = new SendFactory();
Sender sender = factory.produce("sms")';
sender.Send();
}
}
多个工厂方法模式
对普通工厂方法模式的费劲,在普通工厂方法模式中,如果传递的字符串出错,则不能创建对象,而多个工厂方法模式是提供多个工厂方法,分别创建对象
eg:将Factory修改为:
public class SendFactory{
publicSenderproduceMail(){
return new MailSender();
}
publc SenderproduceSms(){
return new SmsSender();
}
}
静态工厂方法模式:
将工厂类中的方法设为静态,不需要创建实例;
抽象工厂模式
普通的工厂方法,类的创建以来于工厂类;扩展程序的时候,需要对工厂类进行修改;
抽象工厂模式,创建多个工厂类,在增加新的功能的时候没直接增加新的工厂类,不需要修改之前的代码;
eg:利用刚才的两个类:
//提供一个接口
public interface Provider{
publicSenderproduce();
}
//创建两个工厂类
public class SendMailFactoryimplements Provider{
@Override
publicSenderproduce(){
return new MailSender();
}
}
public class SendSmsFactoryimplements Provider{
@Override
publicSenderproduce(){
return new SmsSender();
}
}
//Test
public class Test{
public static void main(String[] args){
Provider provider = new SendMailFactory();
Sender sender = provider.produce();
sender.Send();
}
}
建造者模式(Builder)
建造者模式则是将各种产品集中起来进行管理,用来创建复合对象,所谓复合对象就是指某个类具有不同的属性,其实建造者模式就是前面抽象工厂模式和最后的Test结合起来得到的
感觉安卓开发的过程中,好像很经常会用到Builder这个东西;比如说okhttp的FormBody的构造;
eg:
public class Builder{
private List<Sender> list = new ArrayList<Sender>();
public void produceMailSender(intcount){
for(int i=0; i<count; i++){
list.add(new MailSender());
}
}
public void produceSmsSender(intcount){
for(int i=0; i<count; i++){
list.add(new SmsSender());
}
}
}
public class Test{
public static void main(String[] args){
Builder builder = new Builder();
builder.produceMailSender(10);
}
}
还有另一种形式(在effective Java中看到的)
public class NutritionFacts{
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate;
public static class Builder{
// Required parameters
private final int servingSize;
private final int servings;
// Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0;
public Builder(intservingSize,intservings){
this.servingSize = servingSize;
this.servings = servings;
}
publicBuildercalories(intval)
{ calories = val; return this; }
publicBuilderfat(intval)
{ fat = val; return this; }
publicBuildercarbohydrate(intval)
{ carbohydrate = val; return this; }
publicBuildersodium(intval)
{ sodium = val; return this; }
publicNutritionFactsbuild(){
return new NutritionFacts(this);
}
}
private NutritionFacts(Builder builder){
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
}
public static void main(String[] args){
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
}
}
在类的内部定义一个Builder内部类,通过Builder中的函数,设置对象的各种值,最后build为我们的类对象;
感觉这个跟平时开发中用到的东西比较像;
我觉得,利用Builder模式,就解决了多个构造函数的问题
原型模式
该模式的思想就是将一个对象作为原型,对其进行复制、克隆,产生一个和原对象类似的新对象
eg:栗子来自: http://blog.csdn.net/zhangerqing/article/details/8194653
/ **
/ * 原型类
/ **
public class Prototypeimplements Cloneable{
publicObjectclone()throwsCloneNotSupportedException{
Prototype proto = (Prototype) super.clone();
return proto;
}
}
一个原型类,只需要实现Cloneable接口,覆写clone方法,此处clone方法可以改成任意的名称(Cloneable接口是个空接口,你可以任意定义实现类的方法名)
Object类中,clone()是native的
浅复制:将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型,指向的还是原对象所指向的。
深复制:将一个对象复制后,不论是基本数据类型还有引用类型,都是重新创建的。简单来说,就是深复制进行了完全彻底的复制,而浅复制不彻底。
public class Prototypeimplements Cloneable,Serializable{
private static final long serialVersionUID = 1L;
private String string;
private SerializableObject obj;
/* 浅复制 */
publicObjectclone()throwsCloneNotSupportedException{
Prototype proto = (Prototype) super.clone();
return proto;
}
/* 深复制 */
publicObjectdeepClone()throwsIOException, ClassNotFoundException{
/* 写入当前对象的二进制流 */
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
/* 读出二进制流产生的新对象 */
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
return ois.readObject();
}
publicStringgetString(){
return string;
}
public void setString(String string){
this.string = string;
}
publicSerializableObjectgetObj(){
return obj;
}
public void setObj(SerializableObject obj){
this.obj = obj;
}
}
class SerializableObjectimplements Serializable{
private static final long serialVersionUID = 1L;
}
结构型模式
适配器模式
将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作
eg:
public class Mobile
{
/**
* 充电
* @param power
*/
public void inputPower(V5Power power)
{
int provideV5Power = power.provideV5Power();
System.out.println("手机(客户端):我需要5V电压充电,现在是-->" + provideV5Power + "V");
}
}
public interface V5Power
{
public int provideV5Power();
}
public class V220Power
{
/**
* 提供220V电压
* @return
*/
public int provideV220Power()
{
System.out.println("我提供220V交流电压。");
return 220 ;
}
}
适配器:
public class V5PowerAdapterimplements V5Power
{
/**
* 组合的方式
*/
private V220Power v220Power ;
public V5PowerAdapter(V220Power v220Power)
{
this.v220Power = v220Power ;
}
@Override
public int provideV5Power()
{
int power = v220Power.provideV220Power() ;
//power经过各种操作-->5
System.out.println("适配器:我悄悄的适配了电压。");
return 5 ;
}
}
/ **
/ * Test
/ **
public class Test
{
public static void main(String[] args)
{
Mobile mobile = new Mobile();
V5Power v5Power = new V5PowerAdapter(new V220Power()) ;
mobile.inputPower(v5Power);
}
}
桥接模式
将抽象部分与它的实现部分分离,使它们都可以独立地变化。它是一种对象结构型模式,又称为柄体(Handle and Body)模式或接口(Interface)模式。
主要特点是把抽象(abstraction)与行为实现(implementation)分离开来
ClientBridge模式的使用者
Abstraction抽象类接口(接口或抽象类);维护对行为实现(Implementor)的引用
Refined AbstractionAbstraction子类
Implementor行为实现类接口 (Abstraction接口定义了基于Implementor接口的更高层次的操作)
ConcreteImplementorImplementor子类
eg:栗子来自: http://blog.csdn.net/shaopeng5211/article/details/8827507
/ **
/ * implemeentor
/ * 行为实现类接口 (Abstraction接口定义了基于Implementor接口的更高层次的操作)
/ **
public interface Engine{
public void installEngine();
}
/ **
/ * ConcreteImplemeentor
/ * Implementor子类
/ **
public class Engine2000implements Engine{
@Override
public void installEngine(){
...
}
}
public class Engine2200implements Engine{
@Override
public void installEngine(){
...
}
}
/ **
/ * Abstraction
/ * 抽象类接口(接口或抽象类);维护对行为实现(Implementor)的引用
/ **
public abstract class Car{
private Engine engine;
publcCar(Engine engine){
this.engine = engine;
}
publicEnginegetEngine(){
return engine;
}
public void setEngine(Engine engine){
this.engine = engine;
}
public abstract void installEngine();
}
/ **
/ * Refined Abstraction
/ * Abstraction子类
/ **
public class Busextends Car{
public Bus(Engine engine){
super(engine);
}
@Override
public void installEngine(){
...
this.getEngine().installEngine();
}
}
public class Jeepextends Car{
public Jeep(Engine engine){
super(engine);
}
@Override
public void installEngine(){
System.out.print("Jeep:");
this.getEngine().installEngine();
}
}
/ **
/ * Client
/ * Bridge模式的使用者
/ **
public class MainClass{
public static void main(String args[]){
Engine engine2000 = new Engine2000();
Engine engine2200 = new Engine2200();
Car bus = new Bus(engine2000);
bus.installEngine();
Car jeep = new Jeep(engine2200);
jeep.installEngine();
}
}
感觉桥接模式,有点像……画画的时候,有各种笔,然后颜料也有各种颜色;然后不同的笔可以蘸不同的颜料;
装饰者模式
若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上
当我们设计好了一个类,我们需要给这个类添加一些辅助的功能,并且不希望改变这个类的代码,这时候就是装饰者模式大展雄威的时候了
体现了开闭原则
eg:栗子来自: http://blog.csdn.net/lmj623565791/article/details/24269409
这个博主用了游戏系统中装备加宝石,提升属性当做栗子,感觉很有意思;
/**
* 装备的接口
*
* @author zhy
*
*/
public interface IEquip
{
/**
* 计算攻击力
*
* @return
*/
public int caculateAttack();
/**
* 装备的描述
*
* @return
*/
publicStringdescription();
}
/**
* 武器
* 攻击力20
* @author zhy
*
*/
public class ArmEquipimplements IEquip
{
@Override
public int caculateAttack()
{
return 20;
}
@Override
publicStringdescription()
{
return "屠龙刀";
}
}
/**
* 戒指
* 攻击力 5
* @author zhy
*
*/
public class RingEquipimplements IEquip
{
@Override
public int caculateAttack()
{
return 5;
}
@Override
publicStringdescription()
{
return "圣战戒指";
}
}
装饰器:
/**
* 装饰品的接口
* @author zhy
*
*/
public interface IEquipDecoratorextends IEquip
{
}
/**
* 蓝宝石装饰品
* 每颗攻击力+5
* @author zhy
*
*/
public class BlueGemDecoratorimplements IEquipDecorator
{
/**
* 每个装饰品维护一个装备
*/
private IEquip equip;
public BlueGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 5 + equip.caculateAttack();
}
@Override
publicStringdescription()
{
return equip.description() + "+ 蓝宝石";
}
}
/**
* 黄宝石装饰品
* 每颗攻击力+10
* @author zhy
*
*/
public class YellowGemDecoratorimplements IEquipDecorator
{
/**
* 每个装饰品维护一个装备
*/
private IEquip equip;
public YellowGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 10 + equip.caculateAttack();
}
@Override
publicStringdescription()
{
return equip.description() + "+ 黄宝石";
}
}
/**
* 红宝石装饰品 每颗攻击力+15
*
* @author zhy
*
*/
public class RedGemDecoratorimplements IEquipDecorator
{
/**
* 每个装饰品维护一个装备
*/
private IEquip equip;
public RedGemDecorator(IEquip equip)
{
this.equip = equip;
}
@Override
public int caculateAttack()
{
return 15 + equip.caculateAttack();
}
@Override
publicStringdescription()
{
return equip.description() + "+ 红宝石";
}
}
//Test!
package com.zhy.pattern.decorator;
public class Test
{
public static void main(String[] args)
{
// 一个镶嵌1颗红宝石,1颗蓝宝石的武器
System.out.println(" 一个镶嵌1颗红宝石,1颗蓝宝石,1颗黄宝石的武器");
equip = new RedGemDecorator(new BlueGemDecorator(new YellowGemDecorator(new ArmEquip())));
System.out.println("攻击力 : " + equip.caculateAttack());
System.out.println("描述 :" + equip.description());
System.out.println("-------");
}
}
组合模式
将对象组合成树形结构以表示“部分-整体”的层次结构。Composite使得用户对单个对象和组合对象的使用具有一致性。
外观模式
提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用
eg:栗子来自: http://blog.csdn.net/lmj623565791/article/details/25837275
public class HomeTheaterFacade
{
private Computer computer;
private Player player;
private Light light;
private Projector projector;
private PopcornPopper popper;
public HomeTheaterFacade(Computer computer, Player player, Light light, Projector projector, PopcornPopper popper)
{
this.computer = computer;
this.player = player;
this.light = light;
this.projector = projector;
this.popper = popper;
}
public void watchMovie()
{
/**
* 1、打开爆米花机
2、制作爆米花
3、将灯光调暗
4、打开投影仪
5、放下投影仪投影区
6、打开电脑
7、打开播放器
8、将播放器音调设为环绕立体声
*/
popper.on();
popper.makePopcorn();
light.down();
projector.on();
projector.open();
computer.on();
player.on();
player.make3DListener();
}
public void stopMovie()
{
popper.off();
popper.stopMakePopcorn();
light.up();
projector.close();
projector.off();
player.off();
computer.off();
}
}
感觉像是,将要做一件事的所有步骤,整合到一块;
程序猿的技术大观园:www.javathinker.net
|
|