工厂模式
就是专门负责将大量有共同接口的类实例化,而且不必事先知道每次是要实例化哪一个类的模式。
实例一:
- package org.jzkangta.factorydemo01;
- //定义接口
- interface Car{
- public void run();
- public void stop();
- }
- //具体实现类
- class Benz implements Car{
- public void run(){
- System.out.println("Benz开始启动了。。。。。");
- }
- public void stop(){
- System.out.println("Benz停车了。。。。。");
- }
- }
- //具体实现类
- class Ford implements Car{
- public void run(){
- System.out.println("Ford开始启动了。。。");
- }
- public void stop(){
- System.out.println("Ford停车了。。。。");
- }
- }
- //工厂
- class Factory{
- public static Car getCarInstance(){
- return new Ford();
- }
- }
- public class FactoryDemo01 {
- public static void main(String[] args) {
- Car c=Factory.getCarInstance();
- c.run();
- c.stop();
- }
- }
实例二:
- package fac;
- //定义接口
- interface Car{
- public void run();
- public void stop();
- }
- //具体实现类
- class Benz implements Car{
- public void run(){
- System.out.println("Benz开始启动了。。。。。");
- }
- public void stop(){
- System.out.println("Benz停车了。。。。。");
- }
- }
- class Ford implements Car{
- public void run(){
- System.out.println("Ford开始启动了。。。");
- }
- public void stop(){
- System.out.println("Ford停车了。。。。");
- }
- }
- //工厂
- class Factory{
- public static Car getCarInstance(String type){
- Car c=null;
- if("Benz".equals(type)){
- c=new Benz();
- }
- if("Ford".equals(type)){
- c=new Ford();
- }
- return c;
- }
- }
- public class FactoryDemo02 {
- public static void main(String[] args) {
- Car c=Factory.getCarInstance("Benz");
- if(c!=null){
- c.run();
- c.stop();
- }else{
- System.out.println("造不了这种汽车。。。");
- }
- }
- }
- interface Car{
- public void run();
- public void stop();
- }
- class Benz implements Car{
- public void run(){
- System.out.println("Benz开始启动了。。。。。");
- }
- public void stop(){
- System.out.println("Benz停车了。。。。。");
- }
- }
- class Ford implements Car{
- public void run(){
- System.out.println("Ford开始启动了。。。");
- }
- public void stop(){
- System.out.println("Ford停车了。。。。");
- }
- }
- class Toyota implements Car{
- public void run(){
- System.out.println("Toyota开始启动了。。。");
- }
- public void stop(){
- System.out.println("Toyota停车了。。。。");
- }
- }
- class Factory{
- public static Car getCarInstance(String type){
- Car c=null;
- try {
- c=(Car)Class.forName("org.jzkangta.factorydemo03."+type).newInstance();//利用反射得到汽车类型
- } catch (InstantiationException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (IllegalAccessException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- // TODO Auto-generated catch block
- e.printStackTrace();
- }
- return c;
- }
- }
- public class FactoryDemo03 {
- public static void main(String[] args) {
- Car c=Factory.getCarInstance("Toyota");
- if(c!=null){
- c.run();
- c.stop();
- }else{
- System.out.println("造不了这种汽车。。。");
- }
- }
- }
对比三个实例:
实例一,虽然实现了简单工厂,但每次只能得到一种汽车,如果我们想换一种,就得修改工厂,太不方便,而实例二则改变了这种情况,便得我们可以按照我们的需要更换汽车,但我们所更换的汽车必须是实现类中有的,如果我们想要增加一种汽车的时候,我们还是得更改工厂,通过改进,实例三利用反射机制,得到汽车类型,这样当我们需要增加一种新的汽车时,就无需要再修改工厂,而只需要增加要实现的类即可。也就是说要增加什么样的汽车直接增加这个汽车的类即可,而无需改变工厂。从而达到了工厂分离的效果。
(本文参考《java与模式》及〈浪曦〉视频教程,并引用了相关实例)
一、 抽象工厂(Abstract Factory)模式
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。
为了方便引进抽象工厂模式,引进一个新概念:产品族(Product Family)。所谓产品族,是指位于不同产品等级结构,功能相关联的产品组成的家族。如图:
图中一共有四个产品族,分布于三个不同的产品等级结构中。只要指明一个产品所处的产品族以及它所属的等级结构,就可以唯一的确定这个产品。
引进抽象工厂模式
所谓的抽象工厂是指一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象。如果用图来描述的话,如下图:
二、 Abstract Factory模式的结构:
图中描述的东西用产品族描述如下:
抽象工厂(Abstract Factory)角色:担任这个角色的是工厂方法模式的核心,它是与应用系统商业逻辑无关的。
具体工厂(Concrete Factory)角色:这个角色直接在客户端的调用下创建产品的实例。这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
抽象产品(Abstract Product)角色:担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
具体产品(Concrete Product)角色:抽象工厂模式所创建的任何产品对象都是某一个具体产品类的实例。这是客户端最终需要的东西,其内部一定充满了应用系统的商业逻辑。
三、 程序举例:
该程序演示了抽象工厂的结构,本身不具有任何实际价值。
using System;
// "AbstractFactory"
abstract class AbstractFactory
{
// Methods
abstract public AbstractProductA CreateProductA();
abstract public AbstractProductB CreateProductB();
}
// "ConcreteFactory1"
class ConcreteFactory1 : AbstractFactory
{
// Methods
override public AbstractProductA CreateProductA()
{
return new ProductA1();
}
override public AbstractProductB CreateProductB()
{
return new ProductB1();
}
}
// "ConcreteFactory2"
class ConcreteFactory2 : AbstractFactory
{
// Methods
override public AbstractProductA CreateProductA()
{
return new ProductA2();
}
override public AbstractProductB CreateProductB()
{
return new ProductB2();
}
}
// "AbstractProductA"
abstract class AbstractProductA
{
}
// "AbstractProductB"
abstract class AbstractProductB
{
// Methods
abstract public void Interact( AbstractProductA a );
}
// "ProductA1"
class ProductA1 : AbstractProductA
{
}
// "ProductB1"
class ProductB1 : AbstractProductB
{
// Methods
override public void Interact( AbstractProductA a )
{
Console.WriteLine( this + " interacts with " + a );
}
}
// "ProductA2"
class ProductA2 : AbstractProductA
{
}
// "ProductB2"
class ProductB2 : AbstractProductB
{
// Methods
override public void Interact( AbstractProductA a )
{
Console.WriteLine( this + " interacts with " + a );
}
}
// "Client" - the interaction environment of the products
class Environment
{
// Fields
private AbstractProductA AbstractProductA;
private AbstractProductB AbstractProductB;
// Constructors
public Environment( AbstractFactory factory )
{
AbstractProductB = factory.CreateProductB();
AbstractProductA = factory.CreateProductA();
}
// Methods
public void Run()
{
AbstractProductB.Interact( AbstractProductA );
}
}
/// <summary>
/// ClientApp test environment
/// </summary>
class ClientApp
{
public static void Main(string[] args)
{
AbstractFactory factory1 = new ConcreteFactory1();
Environment e1 = new Environment( factory1 );
e1.Run();
AbstractFactory factory2 = new ConcreteFactory2();
Environment e2 = new Environment( factory2 );
e2.Run();
}
}
四、 在什么情形下使用抽象工厂模式:
在以下情况下应当考虑使用抽象工厂模式:
- 一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有形态的工厂模式都是重要的。
- 这个系统有多于一个的产品族,而系统只消费其中某一产品族。
- 同属于同一个产品族的产品是在一起使用的,这一约束必须在系统的设计中体现出来。
- 系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于实现。
五、 抽象工厂的起源
据说最早的应用是用来创建在不同操作系统的视窗环境下都能够运行的系统。比如在Windows与Unix系统下都有视窗环境的构件,在每一个操作系统中,都有一个视窗构件组成的构件家族。我们可以通过一个抽象角色给出功能描述,而由具体子类给出不同操作系统下的具体实现,如图:
可以发现上面产品类图有两个产品等级结构,分别是Button与Text;同时有两个产品族:Unix产品族与Windows产品族。
系统对产品对象的创建要求由一个工厂的等级结构满足。其中有两个具体工厂角色,即UnixFactory和WinFactory。UnixFactory对象负责创建Unix产品族中的产品,而WinFactory负责创建Windows产品族中的产品。
显然一个系统只能够在某一个操作系统的视窗环境下运行,而不能同时在不同的操作系统上运行。所以,系统实际上只能消费属于同一个产品族的产品。
在现代的应用中,抽象工厂模式的使用范围已经大大扩大了,不再要求系统只能消费某一个产品族了。
六、 Abstract Factory模式在实际系统中的实现
Herbivore:草食动物
Carnivore:食肉动物
Bison:['baisn],美洲或欧洲的野牛
下面实际代码演示了一个电脑游戏中创建不同动物的抽象工厂。尽管在不同大陆下动物物种是不一样的,但动物间的关系仍然保留了下来。
using System;
// "AbstractFactory"
abstract class ContinentFactory
{
// Methods
abstract public Herbivore CreateHerbivore();
abstract public Carnivore CreateCarnivore();
}
// "ConcreteFactory1"
class AfricaFactory : ContinentFactory
{
// Methods
override public Herbivore CreateHerbivore()
{ return new Wildebeest(); }
override public Carnivore CreateCarnivore()
{ return new Lion(); }
}
// "ConcreteFactory2"
class AmericaFactory : ContinentFactory
{
// Methods
override public Herbivore CreateHerbivore()
{ return new Bison(); }
override public Carnivore CreateCarnivore()
{ return new Wolf(); }
}
// "AbstractProductA"
abstract class Herbivore
{
}
// "AbstractProductB"
abstract class Carnivore
{
// Methods
abstract public void Eat( Herbivore h );
}
// "ProductA1"
class Wildebeest : Herbivore
{
}
// "ProductB1"
class Lion : Carnivore
{
// Methods
override public void Eat( Herbivore h )
{
// eat wildebeest
Console.WriteLine( this + " eats " + h );
}
}
// "ProductA2"
class Bison : Herbivore
{
}
// "ProductB2"
class Wolf : Carnivore
{
// Methods
override public void Eat( Herbivore h )
{
// Eat bison
Console.WriteLine( this + " eats " + h );
}
}
// "Client"
class AnimalWorld
{
// Fields
private Herbivore herbivore;
private Carnivore carnivore;
// Constructors
public AnimalWorld( ContinentFactory factory )
{
carnivore = factory.CreateCarnivore();
herbivore = factory.CreateHerbivore();
}
// Methods
public void RunFoodChain()
{ carnivore.Eat(herbivore); }
}
/// <summary>
/// GameApp test class
/// </summary>
class GameApp
{
public static void Main( string[] args )
{
// Create and run the Africa animal world
ContinentFactory africa = new AfricaFactory();
AnimalWorld world = new AnimalWorld( africa );
world.RunFoodChain();
// Create and run the America animal world
ContinentFactory america = new AmericaFactory();
world = new AnimalWorld( america );
world.RunFoodChain();
}
}
抽象工厂的另外一个例子:
如何设计抽象类工厂留作思考。
七、 "开放-封闭"原则
"开放-封闭"原则要求系统对扩展开放,对修改封闭。通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
增加产品族:Abstract Factory很好的支持了"开放-封闭"原则。
增加新产品的等级结构:需要修改所有的工厂角色,没有很好支持"开放-封闭"原则。
综合起来,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,而不能为新的产品等级结构的增加提供这样的方便。
参考文献:
阎宏,《Java与模式》,电子工业出版社
[美]James W. Cooper,《C#设计模式》,电子工业出版社
[美]Alan Shalloway James R. Trott,《Design Patterns Explained》,中国电力出版社
[美]Robert C. Martin,《敏捷软件开发-原则、模式与实践》,清华大学出版社
[美]Don Box, Chris Sells,《.NET本质论 第1卷:公共语言运行库》,中国电力出版社
抽象工厂模式:提供一个创建一个一系列相关或互相依赖对象的接口,而无需指定他们具体的类。(针对的是一个系列)
类图:
代码:
产品类:
publicclass AbstractProductA {}
publicclass ProductA1 extends AbstractProductA {}
publicclass ProductA2 extends AbstractProductA{}
publicclass AbstractProductB {}
publicclass ProductB1 extends AbstractProductB {}
publicclass ProductB2 extends AbstractProductB {}
工厂类:
publicinterface IFactory {
AbstractProductA CreateProductA();
AbstractProductB CreateProductB();
}
publicclass ConcreteFactory1 implements IFactory {
@Override
public AbstractProductA CreateProductA() {
returnnew ProductA1();
}
@Override
public AbstractProductB CreateProductB() {
returnnew ProductB1();
}
}
publicclass ConcreteFactory2 implements IFactory {
@Override
public AbstractProductA CreateProductA() {
returnnew ProductA2();
}
@Override
public AbstractProductB CreateProductB() {
returnnew ProductB2();
}
}
优点:可以解决表格型结构对象的创建。如下图:
缺点:抽象工厂结构比较复杂,而且增加一个功能(功能C)就要修改所有的工厂类。
工厂的比较:3个工厂比较像是一个进化的过程!简单工厂针对于单个对象,工厂方法针对抽象对象,而抽象工厂针对的是一个系列的抽象对象。个人感觉抽象工厂其实是相对完善的(完善=复杂)。不是每一个程序都选择完善,而是选择简单。
设计模式-观察者模式
最近用seam框架,发现所有的event都可以通过定义观察者去观察,很好很强大,遂有感研究下设计模式中的观察者模式。GoF说道:Observer模式的意图是“定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新”。
怎么理解呢,简单起见,以家长和老师对学生考试成绩的观察为例。
先定义一个通用观察者接口:
- package com.db.observer;
- public interface ObserverInterface {
- public abstract void update(Student stu);
- }
再定义一个学生类:
- package com.db.observer;
- import java.util.Iterator;
- import java.util.Random;
- public class Student {
- private int score;
- public void changeScore(){
- score = (new Random()).nextInt(100);
- notifyObserver();
- }
- public int getScore() {
- return score;
- }
- private void notifyObserver(){
- if(ObserverGen.oi!=null && !ObserverGen.oi.isEmpty()){
- Iterator<ObserverInterface> e = ObserverGen.oi.iterator();
- while(e.hasNext()){
- e.next().update(this);
- }
- }
- }
- }
再定义两个观察者:一个是家长,一个老师
- package com.db.observer;
- public class ParentOberver implements ObserverInterface{
- @Override
- public void update(Student stu) {
- if(stu.getScore()>80){
- System.out.println("Score="+stu.getScore()+",Parent:^_^");
- }else{
- System.out.println("Score="+stu.getScore()+",Parent:>_<");
- }
- }
- }
- package com.db.observer;
- public class TeacherObserver implements ObserverInterface {
- @Override
- public void update(Student stu) {
- if(stu.getScore()>80){
- System.out.println("Score="+stu.getScore()+",Teacher:You're brilliant!");
- }else{
- System.out.println("Score="+stu.getScore()+",Teacher:Don't be a chicken!");
- }
- }
- }
为了以后可以很方便地添加其他的观察者(比如亲戚,同学,女友等等),应该定义一个观察者注册器:
- package com.db.observer;
- import java.util.ArrayList;
- import java.util.List;
- public class ObserverGen {
- public static List<ObserverInterface> oi = new ArrayList<ObserverInterface>();
- }
- package com.db.observer;
- public class TestObserver {
- public static void main(String[] args) {
- ObserverInterface pob = new ParentOberver();
- ObserverInterface tob = new TeacherObserver();
- ObserverGen.oi.add(pob);
- ObserverGen.oi.add(tob);
- (new Student()).changeScore();
- }
- }
某次运行结果:
Score=99,Parent:^_^
Score=99,Teacher:You're brilliant!
我们可以看到,当学生的成绩发生变化时,所依赖的对象(家长和老师)都及时得到了通知并自动更新了状态。
题外话:Seam框架里定义了很多有用的观察者事件,通过annotations使用起来,非常灵活,这种设计思想很值得我们去借鉴。
设计模式-代理模式
设计模式中定义: 为其他对象提供一种代理以控制对这个对象的访问.(在出发点到目的地之间有一道中间层,意为代理.)
1:抽象主题角色.声明了代理主题和真实主题的公共接口,使任何需要真实主题的地方都能用代理主题代替.
2:代理主题角色.含有真实主题的引用,从而可以在任何时候操作真实主题,代理主题功过提供和真实主题相同的接口,使它可以随时代替真实主题.代理主题通过持有真实主题的引用,不但可以控制真实主题的创建或删除,可以在真实主题被调用前进行拦截,或在调用后进行某些操作.
3:真实代理对象.定义了代理角色所代表的具体对象.
以买票为例:
1.先定义一个公共的买票接口
- package com.db.proxy;
- public interface BuyInterface {
- public void buy();
- }
- package com.db.proxy;
- public class BuyTicket implements BuyInterface {
- @Override
- public void buy() {
- System.out.println("i am buying a ticket.");
- }
- }
- package com.db.proxy;
- public class ProxyBuyTicket implements BuyInterface {
- private BuyTicket bt;
- ProxyBuyTicket(BuyTicket bt){
- this.bt = bt;
- }
- @Override
- public void buy() {
- preRequest();
- System.out.println("i am using proxy to buy a ticket");
- bt.buy();
- postRequest();
- }
- private void preRequest() {
- // something you want to do before requesting
- }
- private void postRequest() {
- // something you want to do after requesting
- }
- }
- package com.db.proxy;
- public class ProxyTest {
- public static void main(String[] args) {
- BuyInterface bi = new ProxyBuyTicket(new BuyTicket());
- bi.buy();
- }
- }
i am using proxy to buy a ticket
i am buying a ticket.
以上是最简单的代理实现,利用java的反射机制,可以实现动态代理。
java主要是通过Proxy类和InvocationHandler接口来给实现对代理模式的支持的。
定义一个动态代理类:
- package com.db.proxy;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- public class DynamicProxyBuyTicket implements InvocationHandler {
- private Object toProxyObj;
- DynamicProxyBuyTicket(Object obj){
- this.toProxyObj = obj;
- }
- public static Object getProxyObject(Object obj){
- @SuppressWarnings("rawtypes")
- Class cls = obj.getClass();
- return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(),new DynamicProxyBuyTicket(obj));
- }
- @Override
- public Object invoke(Object proxy, Method method, Object[] args)
- throws Throwable {
- System.out.println("pre invoke method:" + method);
- if(args!=null){
- //list args
- for(int i=0;i<args.length;i++){
- System.out.println(args[i]);
- }
- }
- //call real obj's method
- method.invoke(toProxyObj, args);
- System.out.println("post invoke method:" + method);
- return null;
- }
- }
- package com.db.proxy;
- public class DynamicProxyTest {
- public static void main(String[] args) {
- BuyInterface bi = (BuyInterface)DynamicProxyBuyTicket.getProxyObject(new BuyTicket());
- bi.buy();
- }
- }
pre invoke method:public abstract void com.db.proxy.BuyInterface.buy()
i am buying a ticket.
post invoke method:public abstract void com.db.proxy.BuyInterface.buy()
关于java的动态代理:
Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:
(1). Interface InvocationHandler:该接口中仅定义了一个方法Object:invoke(Object obj,Method method, Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的request(),args为该方法的参数数组。这个抽象方法在代理类中动态实现。
(2).Proxy:该类即为动态代理类,作用类似于上例中的ProxySubject,其中主要包含以下内容:
Protected Proxy(InvocationHandler h):构造函数,估计用于给内部的h赋值。
Static Class getProxyClass (ClassLoader loader, Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。
所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。(Forest Hou,《Dynamic Proxy 在 Java RMI 中的应用》)