设计模式
介绍常用的设计模式,突破代码约束,从设计模式开始。
设计模式可以分为创建型 结构型 和行为型
创建型主要用于描述如何创建对象。结构性主要用于如何实现类或对象的组合 行为型主要用于描述类或是对象如何交互。
创建型:单例模式 简单工厂模式 工厂模式 工厂方法模式 原型模式 建筑者模式
机构型:适配器模式 桥接模式 组合模式 装饰模式 外观模式 享元模式 代理模式
行为型:解释器模式 职责模式 ,命令模式 迭代器模式 观察者模式 状态模式 策略模式 模板模式 模板方法模式 访问者模式 中介者模式
反射
反射的编程特点:大大的提高了稳定框架的能力。具体变现在,当新增加功能的时候,仅仅增加相应的功能类,而框架调用可能不需要发生变化。
抽象类是对一种事物的抽象,即对类抽象,而接口是对行为的抽象。
public class ReflectionTest {
public static void setObjectColor(Object obj) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAcces***ception, InvocationTargetException{
Class cls = obj.getClass();
//获得类的私有方法
Method method = cls.getDeclaredMethod("privateMethod", null);
method.setAccessible(true); //没有设置就会报错
//调用该方法
method.invoke(obj, null);
}
public static void main(String args[]) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAcces***ception, InvocationTargetException{
setObjectColor(new MyTest());
}
class MyTest{
public void setMyTest(){
System.out.println("setMyTest");
}
/**
类的私有方法
**/
private void privateMethod(){
System.out.println("调用了 private Method");
}
}
单例模式
不管new多少次仅仅创建这个类的一个实例,比如日志记录的管理类 数据库的连接池 日志管理 Runtime类的实现
查看方法执行耗费的系统内存
Runtime runtime = new Runtime.getRuntime();
long start = runtime.freeMemory();
//do something
long end = runtime.freeMemory();
System.out.println(end - start);
单例模式的实现方法其实十分的简单,就是定义一个该类的静态变量,然后再定义一个获取该静态变量的静态方法。
单例模式需要注意的是需要将构造函数定义为private 防止通过构造函数获取该类的实例。
饥饿式单例模式(单线程中使用)
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
}
public static Singleton getInstance()
{
return instance;
}
}
// 单例模式的另一种展示方式
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
}
public static Singleton getInstance()
{
if(instance == null)
{
instance = new Singleton();
}
}
}
// 双检测锁机制的单例模式
//在多线程中使用 if(instance == null)就会出问题
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
}
public static synchronize Singleton getInstance()
{
if(instance == null)
{
instance = new Singleton();
}
}
}
//这种写法也有问题,没运行一个单例就会进行同步,效率非常低
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
}
public static Singleton getInstance()
{
if(instance == null)
{
synchronize (Singleton.class)
instance = new Singleton();
}
}
}
//双检测锁机制
public class Singleton
{
private static Singleton instance = new Singleton();
private Singleton()
{
}
public static Singleton getInstance()
{
if(instance == null)
{
synchronize (Singleton.class)
{
if(instance == null)
instance = new Singleton();
}
}
}
return instance;
}
工厂模式
对象的创建和使用分离,就是简单的工厂模式srping采用的是工厂模式的道理
工厂模式举例:
public class Product
{
private double num;
private double price;
private double total;
public double getNum()
{
return num;
}
public double getPrice()
{
return price;
}
public void setPrice(double price)
{
this.price = price;
}
}
//这样我们在man函数里调用的时候就是:
Product pro =new Product();
pro.setPrice(12);
pro.setNum(234);
如果这个时候我们增加一个折扣率,我们就需要在调用的时候写很多垃圾代码:pro.setPrice(12) * 0.1 等
这个时候我们考虑使用工厂模式 如下
public class Product
{
private double num;
private double price;
private double total;
public double getNum()
{
return num;
}
public double getPrice()
{
return price;
}
private double rebate;
public double getRebate()
{
return rebate;
}
public double getToal()
{
total = num * price *rebate;
return total;
}
public void setPrice(double price)
{
this.price = price;
}
}
抽取出来的工厂代码
public class SimpleFactory
{
public static double getTotal(double num, double price, double rebate)
{
Product pro = new Product();
pro.setNum(0);
pro.setPrice(0);
return pro.getTotal();
}
}
客户调用
System.out.println(SimpleFactory.getTotal(...));
原型模式
如请假单一样 需要很多个请假单,但是每个都一样 仅仅是地址不一样,也就是说如果有一个对象,已经包含了一些初始值,当需要一个和该对象完全相同的新对象。在java中可以很直接将该对象赋值给新对象,但是以为内java地址传递,因此如果修改的新的对象的值,则原来的值也会被修改,如果不希望修改就需要原型模型。
原型模型就是普通的get set方法 然后以对象的形式调用 这样就能够通过get和set修改对象的值和对象的属性
如果将新的对象的值改变后 原来对象的值也会改变,这样就不能达到预期的结果,我们可以通过在get和set的方法中写这样一段代码
public Object clone
[
Object obj = null;
try
{
obj = super.clone;
}
catch(CloneNotSupportedException ex)
{
System.out.println(ex);
}
return obj;
}
原型模型的实现就是通过一个原型对象来表明要 创建的对象类型,然后用复制这个原型对象的方法来创建更多类型的对象
创建者模式
一般用于构造函数,参数过多的情况。
创建者模式就是将一个复杂的对象的构建与它表示分离,使同样的构建过程可以创建不同的表示,而且客户不用知道对象的构建细节。当系统创建一组复杂的对象,而且这个复杂的对象组装起来比较麻烦时,就可以使用创建者模式了。
就像提到的翻译得的例子,如果翻译器需要加入更多的功能,如果都放到工厂中就显得不是很合理,如果能够将这些功能匹配单独抽取出来,放到一个单独的组装类中,就实现了类的单一职能,这就是创建者模式
创建者模式设计4个关键角色: 产品 抽象生成器 具体生成器 指挥者
适配器模式
当一个系统使用另一个外部提供的接口,而这个接口与目前系统使用的接口不兼容,就需要使用适配器模式,适配器模式就是将一个系统的接口转换成另外一种形式。
适配器模式的意图在于,使用不同的接口类所提供的服务Wie客户端提供它所期望的接口。
public interface Target
{
public String Method1(String s1);
public String Method2(String s1);
public String Method3(String s1);
public String Method4(String s1);
public String Method5(String s1);
public String Method6(String s1);
}
当一个用户需要使用Method中一个一个方法的时候需要复写其他的所有方法,这样就给用户带了了极大的不方便。这个时候我们考虑使用适配器模式‘
我们首先建立一个类来实现接口的所有的方法
public class TargetImpl implements Target]
{
public String Meshod1(String si)
{
适配器模式就是将一个系统的接口转换成另一种形式,从而使原来不能直接用的接口,变得可以调用
Junit中使用了适配器模式
门面模式
又成为外观模式,这种模式实现了子模块与客户端的松耦合关系,从而屏蔽了子模块内部的实现细节。
在java框架中有很多的地方读取了XML文件,如果在程序中写了读取xml的代码,那么程序就显得十分的凌乱,此时需要读取xml的代码抽取出来,形成统一的接口,这就是门面模式的统一应用。
门面模式就是为子系统对外提供一组接口提供一个统一的界面,使得其他系统对该系统的访问都通过这一个统一的界面完成。
spring中也大量的使用了门面模式。
一般需要配置或是属性文件的都是门面模式的体现。
代理模式
代理模式就是给一个对象提供一个代理对象,由这个代理对象控制对源对象的引用,使得代理类在客户端和源对象之间起到一个代理的作用,,一般情况下,在开发中需要对一个类或者方法进行额外处理的时候,就需要使用代理模式。
代理模式能够很好的将直接关联的类进行解耦合。
合成模式
又叫做树形模式,就是把部分和和整体的关系用树结构来表示,使得客户端对单个对象和组合对象的使用具有一致性。
如文件夹的复制
享元模式
在编写程序的时候,如果不采用单例模式就会new很多的对象,这对于系统需要使用大量的重复对象,而这些对象要消耗很大的资源的时候,就需要采用享元模式
我们通过一个十分简单的例子看看这个模式的应用
String str1 = "test";
String str2 = "test";
System.out.println(str1 == str2);
结果会输出true 也就是str1 和str2 指向相同的单元,这就是享元模式的体现
装饰模式
有时候开发人员会使用继承来拓展对象的功能,用户的需求是多变得,也就是造成使用继承会造成代码的大范围移动,其实拓展对相爱了的功能,采用组合比继承要好的多。这就是我们要说的装饰模式。
我们来看一段实例的代码
public class Cash
{
public double getCash(String procuct)
{
return 10;
}
}
我们主方法中需要
Cash cash =new Cash();
cash.getCash("sdf");
来获得对象的价格。
如果要进行打折
public class RebateCash extends Cash
{
public double getCash(String product)
{
return super.getCash(product) * 0.1;
}
}
然后修改客户端的调用
如果再减少一块钱呢?该如何解决呢 再写一个继承类 是不是让继承的关系越来越复杂
下面我们用装饰模式来解决这个问题
public interface Cash
{
public double getCash(String product);
}
public class CashImpl implements Cash
{
public double getCash(String product)
{
return 10;
}
Cash cash = new CashImpl();
cash.getCash("test");
public class CashDecorator implements Cash
{
private Cash cash;
public CashDecorator(Cash cash)
{
this.cash = cash;
}
public double getCash(String product)
{
return cash.getCash(product);
}
}
public class RebateCash extends CashDecoratot
{
public RebateCash(Cash cash)
{
super(cash);
}
public double getCash(String product)
{
return super.getCash(product) * 0.1;
}
}
main :
Cash cash = new CashImpl();
CashDecorator rebateCash = new RebateCash(cash);
rebateCash.getCash("test");
迭代器模式
在开发中经常需要将一个对象一个集合中,或者容器中,这个时候通常需要对集合或是同期进行访问,很明显的对集合或是容器的访问就是遍历,这就要用到迭代器模式。
java 中集合的遍历都用到了迭代器模式
访问者模式
访问者模式把数据结构和作用于结构上的操作之间进行解耦,因为增加一个新的操作就意味着增加一个新的访问者,所以增加新的操作很容易。
访问者模式b一般分为四个角色:
IElement 抽象的事物元素功能接口,定义了固定功能方法以及可变公恩那个的接口
Element 具体功能的实现
IVistor 访问接口 为所有访问者声明一个visit方法,用来代表对对象结构添加的功能
Vistor:具体访问者的实现类,实现真正被添加到对象结构中的功能。
职责链模式
职责链模式在程序开发中应用十分广泛,经常使用公文审批,出差报支当中,职责链模式的作用就是将对象各自处理职责的分开。
能够解决if语句过多的事情。