1、单例模式:通过单例模式可以保证系统中一个类只有一个实例。即一个类只有一个对象
单例模式的要点:
(1、私有的构造方法
(2、指向自己实例的私有静态引用
(3、以自己实例为返回值的静态的公有的方法
饿汉单例:在单例类被加载的时候,就实例化一个对象交给自己的引用
懒汉式:在调用取得实例方法的时候才会实例化对象
饿汉式程序:
public class Singleton{
private static Singleton singleton=new Singleton();
private Singleton(){}
public static Singleton getInstance(){
return singleton;
}
}
懒汉式程序:
public class Singleton{
private static Singleton singleton;
private Singleton(){}
public static Singleton getInstance(){
if(singleton==null){
singleton=new Singleton();
}
return singleton;
}
}
如果面对高并发的情况,而采用的是懒汉模式,最好的选择就是双重判断加同步的方式:
public class Singleton{
private static volatile Singleton singleton=null;
private Singleton(){}
public static Singleton getInstance(){
if(singleton==null){
synchronized(SingletonClass.class){
if(singleton==null){
singleton=new Singleton();
}
}
}
return singleton;
}
}
单例的优点:
1.内存中只存在一个对象,节省内存空间
2.避免频繁的创建销毁对象,可以提高性能
3.避免对共享资源的多重占用
4.可以全局访问。
单例的缺点:
1.扩展困难,由于getInstance静态函数没有办法生成子类的实例。如果扩展,只有重写那个类
2.隐式使用引起类结构不清晰
3.导致程序内存泄漏的问题
注意:在运用单例模式的时候,一定注意不能使用反射产生新的单利对象(否则单利将没有意义)
2、工厂模式:这种模式属于创建型模式,它提供了一种创建对象的最佳方式
工厂模式根据抽象程度的不同分为三种:
简单工厂模式(静态工厂模式)
工厂方法模式(多形性工厂)
抽象工厂模式(工具箱)
工厂模式程序:
public interface Car{
void gotowork();
}
public class Bike implements Car{
@Override
public void gotowork(){
System.out.println("骑自行车去上班!");
}
}
public class Bus implements Car{
@Override
public void gotowork(){
System.out.println("坐公交去上班!");
}
}
public interface ICarFactory{
Car getCar();
}
利用了多态
public BikeFactory implements ICarFactory{
@Override
public Car getCar(){
return new Bike();
}
}
public BusFactory implements ICarFactory{
@Override
public Car getCar(){
return new Bus();
}
}
测试类:
public class TestFactory{
@Test
public void Test(){
ICarFactory factory=null;
factory=new BikeFactory();
factory.getCar().gotowork();
factory=new BusFactory();
factory.getCar.gotowork();
}
}
工厂模式的优点:
1.一个调用者想创建一个对象,只要知道其名称就可以,降低了耦合度
2.扩展性高,如果想增加一个产品,只要扩展一个工厂类就可以,使代码结构更清晰
3.屏蔽产品的具体实现,调用者只关心产品的接口
缺点:增加了系统的复杂度,同时也增加了系统具体类的依赖
总结:无论是简单工厂模式,工厂模式还是抽象工厂模式,他们的本质都是将不变的部分提取出来,
将可变的部分留作接口,以达到最大的复用。
3、原型模式:通过复制现有的对象实例来创建新的对象实例
实现:
实现Cloneable接口:
Cloneable接口的作用是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法,在Java
虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常
重写Object类中的clone方法:
Java中,所有类的弗雷都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected
类型的,一般的类无法调用,因此,原型类需要将clone方法的作用域修改为public类型。
原型程序:
public class Mail implements Cloneable{
private String receiver;
private String subject;
private String content;
private String tail;
public Mail(Eventtemplate et){
this.tail=et.geteventContent();
this.subject=et.geteventSubject();
}
@Override
public Mail clone(){
Mail mail=null;
try{
mail=(Mail)super.clone();
} catch(CloneNotSupportedException e){
e.printStacktrace();
return maill;
}
}
}
test:
public static void main(String[] args){
int i=0;
int Max_COUNT=10;
Eventtemplate et=new Eventtemplate("邀请函","诚邀参加我的生日");
Mail mail=new Mail(et);
while(i<Max_COUNT){
Mail cloneMail=mail.clone();
cloneMail.setContent("XXX先生(女士)(变化部分)"+mail.getTail());
cloneMail.setReceiver("每个人的邮箱地址。。。。com(变化部分)");
sendMail(cloneMail);
i++;
}
}
优点:
1.使用原型模型创建一个对象比直接new一个对象更有效率,因为他直接操作内存中的 二进制流,特别是复制大对象时,性能的差别非常明显
2.隐藏了制造新实例的复杂性,使得创建对象就像我们在编辑文档时的复制粘贴一样简单
缺点:
1.原型模式复制对象时不会调用类的构造方法,无法和单例模式组合使用,原型类需要将clone方法的作用域修改为public
2.使用原型模式时不能有final对象
3.Object类的clone方法只会拷贝对象中的基本数据类型,对于数组,引用类型等只能另行拷贝
浅拷贝:
将一个对象复制后,基本数据类型的变量都会重新创建,而引用类型指向的还是原对象所指向的
深拷贝:
将一个对象复制后,不论是基本数据类型还是引用类型,都是重新创建的
4、生成器模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示 。
生成器模式利用一个导演者对象和具体建造者对象一个一个地建造出所有的零件,从而建造出完整的对象四个要素:
Builder:生成器接口,定义创建一个Product对象所需要的各部件的操作。
ConcreteBuilder;具体的生成器实现,实现各个部件的创建,并负责组装Product对象的各个部件,同时
还提供一个让用户获取组装完成后的产品对象的方法
Director:指导者。也被称导向者,主要用来使用Builder接口,以一个统一的过程来构建所需要的Product对象
Product;产品,表示被生成器构建的复杂对象,包含多个部件
public class Entity1{}
public class Entity2{}
public class Entity3{}
public class Product{
Entity1 entity1;
Entity2 entity2;
Entity3 entity3;
}
public interface IBuild{
public void createEntity1();
public void createEntity2();
public void createEntity3();
public Product composite();
public Product create();
}
public class BuildProduct implements IBuild{
Product p=new Product();
public void createEntity1(){
}
public Product create(){
return composite();
}
}
public class BuildProduct1 implements IBuild{
Product p =new Product();
public void createEntity1(){
}
}
Test
public class Director{
private IBuild build;
public Director(IBuild build){
this.build=build;
}
public Product build(){
build.create();
}
public static void main(){
IBuild build=new BuildProduct();
Director director=new Director(build);
Product p =director.build();
}
}
优点:
1.使用生成器模式可以使客户端不必知道产品内部组成的细节
2.具体的建造者类之间是相互独立的,对系统的扩展非常有利
3.由于具体的建造者是独立的,因此可以对建造过程逐步细化,而不是对其他的模式产生任何影响
缺点:建造者模式的“加工工艺”是暴露的,这样使得建造者模式更加灵活,也使得工艺变得对客户不透明
5、适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作
角色:
目标(target)角色:这就是所期待得到的接口,也就是这类的接口符合我们的要求
源(Adaopee)角色:我们要使用的接口,但是这个接口不符合我们的要求,也就是现在需要适配的接口
适配器(Adaper)角色:适配器类是适配器模式的核心。适配器把源接口转换成目标接口,显然这一角色不可以是接口,而必须是具体类
1、类适配器模式
class Adaptee{
public void specificRequest(){
System.out.println("特殊请求,这个源是角色");
}
}
/*这个是目标角色,所期待的接口**/
interface Target{
public void request();
}
class Adapter extends Adaptee implements Target{
public void request(){
super.specificRequest();
}
}
@Test
public class Test{
public static void main(String[] args){
//使用特殊功能的类即适配器
Target adapter =new Adapter();
adapter.request();
}
}
2、对象适配器:适配器类关联已有的Adaptee类,并且实现标准接口这样做的好处是不需要继承
class Adapter implements Target{
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee=adaptee;
}
public void request(){
this.adaptee.specificRequest();
}
}
@Test
public class Test{
public static void main(String[] args){
Adaptee adaptee=new Adaptee();
Target adapte=new Adapter(adaptee);
adapte.request;
}
}
区别:
对象的适配器模式不是使用继承关系连接到Adaptee类,而是使用委派关系连接到Adaptee类
优点:
复用性:系统需要使用现有的类,而此类的接口不符合系统的需求,那么可以通过适配器让这些功能复用
扩展性:在实现适配器功能的时候,可以自由调用自己开发的功能,从而自然地扩展系统的功能
缺点:过多的使用适配器,会让系统非常的凌乱,不易整体进行把握
6、装饰者模式:在不必改变原类文件和原类使用的继承情况下,动态的扩展一个对象的功能
它是通过创建一个包装对象,也就是用装饰来包裹真实的对象来实现的
角色:
抽象构件角色:给出一个接口,以规范准备接收附加责任的对象
具体构建角色:定义一个将要接收附加责任的类
装饰角色:持有一个构建对象的实例,并定义一个与抽象构建接口一致的接口
具体装饰角色:负责给构建对象“贴上”附加的责任
公共接口:
public interface Person{
void eat();
}
被装饰对象:
public class OldPersion implements Person{
@Override
public void eat(){
System.out.println("吃饭");
}
}
装饰对象:
public class NewPerson implements Person{
private OldPerson p;
NewPerson(OldPerson p){
this.p=p;
}
@Override
public void eat(){
System.out.println("生火");
System.out.println("做饭");
p.eat();
System.out.println("刷碗");
}
}
测试:
public class PersonDemo{
public static void main(String[] args){
OldPersion old=new OldPerson();
NewPerson n=new NewPerson(old);
n.eat();
}
}
优点:
1.使用装饰着模式比使用继承更加灵活,因为他选择通过一种动态的方式扩展一个对象的功能,在运行时可以选择不同的装饰器,从而实现不同的行为
2.通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合,可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象
3.具体构建类与具体装饰类可以独立变化,他能是低耦合的。用户可以根据需要来增加新的具体构建类和具体装饰类,在使用时再对其进行各种组合
缺点:
1.会产生很多的小对象,增加了系统的复杂性
2.这种比继承更加灵活机动的特性,同时意味着装饰模式比继承更加易于出错,排错也很困难
3.适配器是知道被适配者的详细情况
装饰者和继承的区别:
优点:代码结构清晰,而且实现简单
缺点:对于每一个的需要增强的类都要创建具体的子类来帮助其增强,这样会导致继承体系过于庞大
装饰者:
优点: 内部可以通过多态技术对多个需要增强的类进行增强
缺点:需要内部通过多态技术维护需要增强的类的实例,进而使得代码稍微复杂
7、代理模式:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象
而代理对象可以在客户端和目标对象之间起到中介的作用
角色:
1.抽象角色:声明真实对象和代理对象的共同接口
2.代理角色:代理对象角色内部含有真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替
真实对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于真实对象进行封装
3.真实角色:代理角色所代表的真实对象,是我们最终要引用的对象
分类:
静态代理
静态代理也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托的关系在运行前就确定了
程序:
public interface UserInfo{
public void queryUser();
public void updateUser();
}
真实角色:
public class UserImpl implements UserInfo{
@Override
public void queryUser(){
}
@Override
public void updateUser(){
}
}
代理角色:
public class UserProxy implements UserInfo{
private UserInfo userImpl;
UserProxy(UserInfo userImpl){
this.userImpl=userImpl;
}
@Override
public void queryUser(){
}
@Override
public void updateUser(){
}
}
Test:
public class Test{
public static void main(String[] args){
UserInfo userImpl=new UserImpl();
UserProxy userproxy=new UserProxy(userImpl);
userproxy.queryUser();
userproxy.updateUser();
}
}
动态代理:
抽象的共同接口
public interface UserInfo{
public void queryUser();
public void updateUser();
}
真实的角色
public class UserImpl implements UserInfo{
@Override
public void queryUser(){
}
@Override
public void updateUser(){
}
}
代理角色处理器:
public class UserHandler implements InvocationHandler{
private UserInfo userImpl;
public UserHandler(UserInfo userImpl2){
this.userImpl=userImpl2;
}
@Override
public Object invoke(Object proxy,Method method,Object[] args)throws Throwable{
Object object=null;
if(method.getName().equals("queryUser")){
object=method.invoke(userImpl,args);
}
return object;
}
}
public class test{
public static void main(String[] args){
UserInfo userImpl=new UserImpl();
UserHandler uh=new UserHandler(userImpl);
UserInfo userProxy=(UserInfo) Proxy.newProxyInstan ce(ClassLoader.getSystemClassLoader(),newClass[]{UserInfo.class},handler);
userProxy.queryUser();
}
}
优点:
业务类只需要关注业务逻辑本身,保证了业务类的重要性,这是代理的共有优点
能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。
缺点: 由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢,例如保护代理
8、外观模式:为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用
角色:
1.外观角色:客户端可以调用这个角色的方法
2.子系统角色:可以同时有一个或者多个子系统。每个子系统都不是一个单独的类,而是一个类的集合。
每个子系统都可以被客户端直接调用,或者被外观角色调用,子系统并不知道外观角色的存在,对于子系统而言,
外观角色仅仅是另外一个客户端而已
子系统角色:
public class SubClass1{
public void method1(){
System.out.println("这是子系统类1中的方法1");
}
public void method2(){
System.out.println("这是子系统类1中的方法2");
}
}
public class SubClass2{
public void method1(){
System.out.println("这是子系统类2中的方法1");
}
public void method2(){
System.out.println("这是子系统类2中的方法2");
}
}
public class SubClass3{
public void method1(){
System.out.println("这是子系统类3中的方法1");
}
public void method2(){
System.out.println("这是子系统类3中的方法2");
}
}
外观类
public class FacadeClass{
public void FacadeMethod(){
SubClass1 s1=new SubClass1();
s1.method1();
SubClass2 s2=new SubClass2();
s2.method2();
SubClass3 s3=new SubClass3();
s3.method3();
}
}
优点: 实现了子系统与客户端之间的松耦合关系
客户端屏蔽了子系统组建,减少了客户端所需处理的对象数目,并使得子系统使用起来更加容易
外观模式总结:
1.外观模式为复杂子系统提供一个简单接口,并不是为子系统添加新的功能和行为
2.外观模式实现了子系统与客户端之间的松耦合关系
3.外观模式没有封装子系统的类,只是提供了简单的接口,如果应用需要,它并不是限制客户使用子系统
,因此可以灵活的在系统易用性与通用性之间选择
4。外观模式注重的是简化接口,他更多的时候是从架构的层次去看整个系统,而并非单个类的层次
9、桥接模式:将抽象部分与实现部分分离,使他们都可以独立的变化,桥接模式是一种结构式模式
程序:
interface Implementor{
public void operationImpl();
}
abstract class Abstraction{
protected Implementor implementor;
public Abstraction(Implementor implementor){
this.implementor=implementor;
}
public void operation(){
implementor.operationImpl();
}
}
class ConcreteImplementorA implements Implementor{
@Override
public void operationImpl(){
System.out.println("具体的实现A");
}
}
class ConcreteImplementorB implements Implementor{
@Override
public void operationImpl(){
System.out.println("具体的实现B");
}
}
class RefinedAbstration extends Abstraction{
public RefinedAbstration(Implementor implementor){
super(implementor);
}
public void otherOperation(){
//实现一定的功能,可能会使用具体的实现方法
//但是本方法更大的可能是使用Abstraction 中定义的方法
//通过组合使用Abstration中定义的方法来完成更多的功能
}
}
public class BridgePattern{
public static void main(String[] args){
Implementor implementor=new ConcreteImplementorA();
RefinedAbstration abstraction=new RefinedAbstration(implementor);
abstraction.operation();
abstraction.otherOperation();
}
}
10、组合模式:可以优化处理递归或分级数据结构,有许多关于分级数据结构的例子,使得组合模式非常有用武之地
Componet:为参加组合的对象声明一个公共接口,不管是组合还是叶结点
Leaf:在组合中表示叶子结点对象,叶子结点没有子结点
Composite:表示参加组合的有子对象的对象,并给出树枝构建的行为
实例:
FolderComponent
public abstract class FolderComponent{
private String name;
public String getName(){
return name;
}
public void setName(final String name){
this.name=name;
}
public FolderComponent(){
}
public FolderComponent(final String name){
this.name=name;
}
public abstract void add(FolderComponent component);
public abstract void remove(FolderComponent component);
public abstract void display();
}
FileLeaf
public class FileLeaf extends FolderComponent{
public FileLeaf(final String name){
super(name);
}
@Override
public void add(final FolderComponent component){}
@Override
public void remove(final FOlderComponent component){
}
@Override
public void display(){
System.out.println("FileLeaf:"+this.getName());
}
}
FolderComposite
public class FolderComposite extends FolderComponent{
private final List<FolderComponent> components;
public FolderComposite(final String name){
super(name);
this.components=new ArrayList<FolderComponent>();
}
public FolderComposite(){
this.components=new AarryList<FolderComponent>();
}
@Override
public void add(final FolderComponent component){
this.components.add(component);
}
@Override
public void remove(final FolderComponent component){
this.components.remove(component);
}
@Override
public void display(){
System.out.println("FolderComposite---name:"+this.getName());
for(final FolderComponent component:components){
System.out.println("FolderComposite--component--name:"+component.getName());
}
}
}
Client
public class Client{
public static void main(final String[] args){
final FolderComponent leaf=new FileLeaf("runnable file");
leaf.display();
final FolderComponent folder=new FolderComposite("new folder");
folder.add(new FileLeaf("content1 in new folder"));
folder.add(new FileLeaf("content2 in new folder"));
folder.display();
}
}
总结:组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以向处理简单元素一样来处理复杂元素
如果你想要创建层次结构,并可以在其中矣相同的方式对待所有元素
11、策略模式:定义一组算法,将每个算法都封装起来,并且使他们之间可以互换
策咯模式是对算法的封装,把一系列的算法分别封装到对应的类中,并且这些类实现相同的接口,相互之间可以替换。 策略模式的结构
封装类:对策略进行二次封装,目的是避免高层模块对策略的直接调用
抽象策略:通常情况下为一个接口,当各个实现类中存在着重复的逻辑时,则使用抽象类来封装这部分公共的代码
具体策略:具体策略角色通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换
程序:
interface IStrategy{
public void doSomething();
}
class ConcreteStrategy1 implements IStrategy{
@Override
public void doSomething(){
SYstem.out.println("具体的策略1");
}
}
class ConcreteStrategy2 implements Istrategy{
@Override
public void doSomething(){
System.out.println("具体的策略2");
}
}
class Context{
private IStrategy strategy;
public Context(IStrategy strategy){
this.strategy=strategy;
}
public void execute(){
strategy.doSomething;
}
}
public class Client{
public static void main(String[] args){
Context con;
System.out.println("执行策略1");
con=new Context(new ConcreteStrategy1(););
con.execute();
System.out.println("执行策略2");
con=new Context(new ConcreteStrategy2());
con.execute();
}
}
策略模式的主要优点有:
策略之间可以互相切换,由于策略类主要实现同一个抽象,所以他们之间可以自由切换
易于扩展,增加一个新的策略对策略模式来说非常容易,基本上可以在不改变源代码的基础上进行扩展
避免使用多重条件,如果不使用策略模式,对于所有的算法必须使用条件语句进行连接
策略模式的缺点主要有两个:
维护各个策略类会给开发带来额外的开销
必须对客户端(调用者)暴露所有的策略类,因为使用哪种策略是由客户端来决定的,因此,客户端应该知道有什么策略,并且了解各种策略之间的区别,否则,后果很严重。
12、模板方法模式:定义一个操作中算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变算法的结构,即可以重定义该算法中的某些特定的步骤
abstract class AbstractSort{
protected abstract void sort(int[] array);
public void showSortResult(int[] array){
this.sort(array);
System.out.println("输出排序结果");
for(int i=0;i<array.length;i++){
System.out.println("%3s",array[i]);
}
}
}
class ConcreteSort extends AbstractSort{
@Override
protected void sort(int[] array){
for(int i=0;i<array.length-1;i++){
selectSort(array,i);
}
}
/**这个是把数组里的最小的找到放到前边,然后一个个找小的**/
private void selectSort(int[] array,int index){
int MinValue=32767;
int indexMin=0;
int temp;
for(int i=index;i<array.length;i++){
if(array[i]<MinValue){
MinValue=array[i];
indexMin=i;
}
}
Temp=array[index];
array[index]=array[indexMin];
array[indexMin]=Temp;
}
}
13、观察者模式:定义对象间一种一对多的依赖关系,使得当每一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新
```java
public abstract class Subject{
private Vector<Observer> obs=new Vector<Observer>();
public void addObserver(Observer obs){
this.obs.add(obs);
}
public void delObserver(Observer obs){
this.obs.remove(obs);
}
protected void notifyObserver(){
for(Observer o:objs){
o.update();
}
}
public abstract void doSomething();
}
public class ConcreteSubject extends Subject{
public void doSomething(){
System.out.println("被观察者事件发生");
this.notifyObserver();
}
}
public interface Observer{
public void update();
}
public class ConcreteObserver1 implements Observer{
public void update(){
System.out.println("观察者1收到信息,并进行处理");
}
}
public class ConcreteObserver2 implements Observer{
public void update(){
System.out.println("观察者2收到信息,并进行处理");
}
}