网站开发制作,社交网站制作,天津制作企业网站的,建设注册管理中心网站首页一、引子 话说十年前#xff0c;有一个爆发户#xff0c;他家有三辆汽车#xff08;Benz#xff08;奔驰#xff09;、Bmw#xff08;宝马#xff09;、Audi#xff08;奥迪#xff09;#xff09;#xff0c;还雇了司机为他开车。不过#xff0c;爆发户坐车时总是… 一、引子 话说十年前有一个爆发户他家有三辆汽车Benz奔驰、Bmw宝马、Audi奥迪还雇了司机为他开车。不过爆发户坐车时总是这样上Benz车后跟司机说“开奔驰车”坐上Bmw后他说“开宝马车”坐上 Audi后他说“开奥迪车”。 你一定说这人有病直接说开车不就行了而当把这个爆发户的行为放到我们程序语言中来我们发现C语言一直是通过这种方式来坐车的 幸运的是这种有病的现象在OO语言中可以避免了。下面以Java语言为基础来引入我们本文的主题工厂模式 二、简介 工厂模式主要是为创建对象提供了接口。工厂模式按照《Java与模式》中的提法分为三类 1. 简单工厂模式(Simple Factory) 2. 工厂方法模式(Factory Method) 3. 抽象工厂模式(Abstract Factory) 这三种模式从上到下逐步抽象并且更具一般性。还有一种分类法就是将简单工厂模式看为工厂方法模式的一种特例两个归为一类。两者皆可这本为使用《Java与模式》的分类方法。 在什么样的情况下我们应该记得使用工厂模式呢大体有两点 1.在编码时不能预见需要创建哪种类的实例。 2.系统不应依赖于产品类实例如何被创建、组合和表达的细节 工厂模式能给我们的OOD、OOP带来哪些好处呢 三、简单工厂模式 这个模式本身很简单而且使用在业务较简单的情况下。一般用于小项目或者具体产品很少扩展的情况这样工厂类才不用经常更改。 它由三种角色组成 工厂类角色这是本模式的核心含有一定的商业逻辑和判断逻辑根据逻辑不同产生具体的工厂产品。如例子中的Driver类。 抽象产品角色它一般是具体产品继承的父类或者实现的接口。由接口或者抽象类来实现。如例中的Car接口。 具体产品角色工厂类所创建的对象就是此角色的实例。在java中由一个具体类实现如例子中的Benz、Bmw类。 一个简单工厂可以创建多个具体的产品, 来用类图来清晰的表示下的它们之间的关系 下面就来给那个暴发户治病在使用了简单工厂模式后现在暴发户只需要坐在车里对司机说句“开车”就可以了。来看看怎么用代码实现的为方便起见所有的类放在一个文件中故有一个类被声明为public //抽象产品
abstract class Car{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
//具体产品
class Benz extends Car{ public void drive(){ System.out.println(this.getName()----go-----------------------); }
} class Bmw extends Car{ public void drive(){ System.out.println(this.getName()----go-----------------------); }
} //简单工厂
class Driver{ public static Car createCar(String car){ Car c null; if(Benz.equalsIgnoreCase(car)) c new Benz(); else if(Bmw.equalsIgnoreCase(car)) c new Bmw(); return c; }
} //老板, 客户端, 使用者
public class BossSimplyFactory { public static void main(String[] args) throws IOException { //老板告诉司机我今天坐奔驰 Car car Driver.createCar(benz); car.setName(benz); //司机开着奔驰出发 car.drive(); } 如果老板要坐奥迪同理。 这便是简单工厂模式了。那么它带了了什么好处呢 首先符合现实中的情况而且客户端免除了直接创建产品对象的责任而仅仅负责“消费”产品正如暴发户所为。 下面我们从开闭原则上来分析下简单工厂模式。当暴发户增加了一辆车的时候只要符合抽象产品制定的合同那么只要通知工厂类知道就可以被客户使用了。即创建一个新的车类继承抽象产品Car那么 对于产品部分来说它是符合开闭原则的——对扩展开放、对修改关闭但是工厂类不太理想因为每增加一辆车都要在工厂类中增加相应的商业逻辑和判 断逻辑这显自然是违背开闭原则的。 而在实际应用中很可能产品是一个多层次的树状结构。由于简单工厂模式中只有一个工厂类来对应这些产品随着产品越来越多, 所以这可能会把我们的上帝类坏了。 正如我前面提到的简单工厂模式适用于业务简单的情况下或者具体产品很少增加的情况。而对于复杂的业务环境可能不太适应了。这就应该由工厂方法模式来出场了 四、工厂方法模式 抽象工厂角色 这是工厂方法模式的核心它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 具体工厂角色它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。 抽象产品角色它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 具体产品角色具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 来用类图来清晰的表示下的它们之间的关系 抽象工厂对应抽象产品, 一个具体的工厂只生成一种产品: 话说暴发户生意越做越大自己的爱车也越来越多。这可苦了那位司机师傅了什么车它都要记得维护都要经过他来使用于是暴发户同情他说我给你分配几个人手你只管管好他们就行了于是工厂方法模式的管理出现了。代码如下 //抽象产品
abstract class Car{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
//具体产品
class Benz extends Car{ public void drive(){ System.out.println(this.getName()----go-----------------------); }
}
class Bmw extends Car{ public void drive(){ System.out.println(this.getName()----go-----------------------); }
} //抽象工厂
abstract class Driver{ public abstract Car createCar(String car) throws Exception;
}
//具体工厂每个具体工厂负责一个具体产品
class BenzDriver extends Driver{ public Car createCar(String car) throws Exception { return new Benz(); }
}
class BmwDriver extends Driver{ public Car createCar(String car) throws Exception { return new Bmw(); }
} //老板
public class Boss{ public static void main(String[] args) throws Exception { Driver d new BenzDriver(); Car c d.createCar(benz); c.setName(benz); c.drive(); }
} 使用开闭原则来分析下工厂方法模式。当有新的产品即暴发户的汽车产生时只要按照抽象产品角色、抽象工厂角色提供的合同来生成那么就可以被客户使用而不必去修改任何已有的代码。即当有新产品时只要创建并基础抽象产品新建具体工厂继承抽象工厂而不用修改任何一个类工厂方法模式是完全符合开闭原则的 使用工厂方法模式足以应付我们可能遇到的大部分业务需求。但是当产品种类非常多时就会出现大量的与之对应的工厂类这不应该是我们所希望的。所以我建议在这种情况下使用简单工厂模式与工厂方法模式相结合的方式来减少工厂类即对于产品树上类似的种类一般是树的叶子中互为兄弟的使用简单工厂模式来实现。 当然特殊的情况就要特殊对待了对于系统中存在不同的产品树而且产品树上存在产品族下一节将解释这个名词。那么这种情况下就可能可以使用抽象工厂模式了。 五、小结 让我们来看看简单工厂模式、工厂方法模式给我们的启迪 如果不使用工厂模式来实现我们的例子也许代码会减少很多——只需要实现已有的车不使用多态。但是在可维护性上可扩展性上是非常差的你可以想象一下添加一辆车后要牵动的类。因此为了提高扩展性和维护性多写些代码是值得的。 六、抽象工厂模式 先来认识下什么是产品族 位于不同产品等级结构中功能相关联的产品组成的家族。 图中的BmwCar和BenzCar就是两个产品树产品层次结构而如图所示的BenzSportsCar和BmwSportsCar就是一个产品族。他们都可以放到跑车家族中因此功能有所关联。同理BmwBussinessCar和BenzBusinessCar也是一个产品族。 可以这么说它和工厂方法模式的区别就在于需要创建对象的复杂程度上。而且抽象工厂模式是三个里面最为抽象、最具一般性的。抽象工厂模式的用意为给客户端提供一个接口可以创建多个产品族中的产品对象。 而且使用抽象工厂模式还要满足一下条件 1.系统中有多个产品族而系统一次只可能消费其中一族产品 2.同属于同一个产品族的产品以其使用。 来看看抽象工厂模式的各个角色和工厂方法的如出一辙 抽象工厂角色 这是工厂方法模式的核心它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。 具体工厂角色它含有和具体业务逻辑有关的代码。由应用程序调用以创建对应的具体产品的对象。在java中它由具体的类来实现。 抽象产品角色它是具体产品继承的父类或者是实现的接口。在java中一般有抽象类或者接口来实现。 具体产品角色具体工厂角色所创建的对象就是此角色的实例。在java中由具体的类来实现。 一个工厂中生成一类产品. //抽象产品Bmw和Audi同理
abstract class BenzCar{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
//具体产品Bmw和Audi同理
class BenzSportCar extends BenzCar{ public void drive(){ System.out.println(this.getName()----BenzSportCar-----------------------); }
}
class BenzBusinessCar extends BenzCar{ public void drive(){ System.out.println(this.getName()----BenzBusinessCar-----------------------); }
} abstract class BmwCar{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
class BmwSportCar extends BmwCar{ public void drive(){ System.out.println(this.getName()----BmwSportCar-----------------------); }
}
class BmwBusinessCar extends BmwCar{ public void drive(){ System.out.println(this.getName()----BmwBusinessCar-----------------------); }
} abstract class AudiCar{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
class AudiSportCar extends AudiCar{ public void drive(){ System.out.println(this.getName()----AudiSportCar-----------------------); }
}
class AudiBusinessCar extends AudiCar{ public void drive(){ System.out.println(this.getName()----AudiBusinessCar-----------------------); }
} //抽象工厂
abstract class Driver3{ public abstract BenzCar createBenzCar(String car) throws Exception; public abstract BmwCar createBmwCar(String car) throws Exception; public abstract AudiCar createAudiCar(String car) throws Exception;
}
//具体工厂
class SportDriver extends Driver3{ public BenzCar createBenzCar(String car) throws Exception { return new BenzSportCar(); } public BmwCar createBmwCar(String car) throws Exception { return new BmwSportCar(); } public AudiCar createAudiCar(String car) throws Exception { return new AudiSportCar(); }
}
class BusinessDriver extends Driver3{ public BenzCar createBenzCar(String car) throws Exception { return new BenzBusinessCar(); } public BmwCar createBmwCar(String car) throws Exception { return new BmwBusinessCar(); } public AudiCar createAudiCar(String car) throws Exception { return new AudiBusinessCar(); }
} //老板
public class BossAbstractFactory { public static void main(String[] args) throws Exception { Driver3 d new BusinessDriver(); AudiCar car d.createAudiCar(); car.drive(); }
} 其中BenzSportCar和BenzBusinessCar属于产品树同理BmwSportCar和BmwBusinessCar。而BenzSportCar和BmwSportCar和AudiSportCar属于产品族。 所以抽象工厂模式一般用于具有产品树和产品族的场景下。 抽象工厂模式的缺点如果需要增加新的产品树那么就要新增三个产品类比如VolvoCarVolvoSportCar,VolvoSportCar并且要修改三个工厂类。这样大批量的改动是很丑陋的做法。 所以可以用简单工厂配合反射来改进抽象工厂 abstract class BenzCar{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
class BenzSportCar extends BenzCar{ public void drive(){ System.out.println(this.getName()----BenzSportCar-----------------------); }
}
class BenzBusinessCar extends BenzCar{ public void drive(){ System.out.println(this.getName()----BenzBusinessCar-----------------------); }
} abstract class BmwCar{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
class BmwSportCar extends BmwCar{ public void drive(){ System.out.println(this.getName()----BmwSportCar-----------------------); }
}
class BmwBusinessCar extends BmwCar{ public void drive(){ System.out.println(this.getName()----BmwBusinessCar-----------------------); }
} abstract class AudiCar{ private String name; public abstract void drive(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
class AudiSportCar extends AudiCar{ public void drive(){ System.out.println(this.getName()----AudiSportCar-----------------------); }
}
class AudiBusinessCar extends AudiCar{ public void drive(){ System.out.println(this.getName()----AudiBusinessCar-----------------------); }
} /** * 简单工厂通过反射改进抽象工厂及其子工厂 * author Administrator * */
class Driver3{ public static BenzCar createBenzCar(String car) throws Exception { return (BenzCar) Class.forName(car).newInstance(); } public static BmwCar createBmwCar(String car) throws Exception { return (BmwCar) Class.forName(car).newInstance(); } public static AudiCar createAudiCar(String car) throws Exception { return (AudiCar) Class.forName(car).newInstance(); }
}
//客户端
public class SimpleAndAbstractFactory { public static void main(String[] args) throws Exception { AudiCar car Driver3.createAudiCar(com.java.pattendesign.factory.AudiSportCar); car.drive(); }
} 策略模式
从策略一词来看,策略模式是种倾向于行为的模式.封装不同的算法以打仗为例, 一般司令员在做战前都会根据实际情况做出几套不同的方案如果当时情况有变就会根据相应的条件来判定用哪一套方案来替换原定方案。但无论如何替换替换多少次仗还是要打的。 举例导出成EXCELWORDPDF文件的功能这三类导出虽然具体操作略有不同但是大部分都相同。 策略模式与工厂模式从uml图上来说基本一致。只是强调的封装不同。我们以工厂模式和策略模式的比较来讲解策略模式。 工厂模式我们可以做如下理解假设有Audi的公司生产汽车它掌握一项核心的技术就是生产汽车另一方面它生产的汽车是有不同型号的并且在不同的生产线上进行组装。当客户通过销售部门进行预定后Audi公司将在指定的生产线上为客户生产出它所需要的汽车。 策略(Strategy)模式在结构上与工厂模式类似唯一的区别是工厂模式实例化一个产品的操作是在服务端来做的换句话说客户端传达给服务端的只是某种标识服务端根据该标识实例化一个对象。而策略模式的客户端传达给服务端的是一个实例服务端只是将该实例拿过去在服务端的环境里执行该实例的方法。这就好比一个对汽车不甚了解的人去买车他在那一比划说要什么什么样的销售部门根据他的这个“比划”来形成一份订单这就是工厂模式下的工作方式。而策略模式下那个顾客就是个行家他自己给出了订单的详细信息销售部门只是转了一下手就交给生产部门去做了。通过两相对比我们不难发现采用工厂模式必须提供足够灵活的销售部门如果用户有了新的需求销售部门必须马上意识到这样才可以做出合适的订单。所以倘一款新车出来了生产部门和销售部门都需要更新对顾客来说也需要更新对新车的描述所以需要改动的地方有三处。而策略模式中的销售部门工作比较固定它只负责接受订单并执行特定的几个操作。当一款新车出来时只需要对服务端的生产部门和客户端的代码进行更新而不需要更新销售部门的代码。 技术支持 简单工厂和策略的基础都是因为面向对象的封装与多态。他们实现的思想都是先设定一个抽象的模型并从该模型派生出符合不同客户需求的各种方法并加以封装。 工厂模式和策略模式的区别在于实例化一个对象的位置不同对工厂模式而言实例化对象是放在服务端的即放在了工厂类里面 而策略模式实例化对象的操作在客户端服务端的“销售部门”只负责传递该对象并在服务端的环境里执行特定的操作。。。 工厂模式要求服务端的销售部门足够灵敏而策略模式由于对策略进行了封装所以他的销售部门比较傻需要客户提供足够能区分使用哪种策略的参数而这最好的就是该策略的实例了。 //抽象产品
abstract class AudiCar{ private String name; public abstract void makeCar(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
//具体产品
class AudiA6 extends AudiCar{ public void makeCar(){ System.out.println(this.getName()----go-----------------------); }
}
class AudiA4 extends AudiCar{ public void makeCar(){ System.out.println(this.getName()----go-----------------------); }
} //销售部门----服务端
class CarContext { AudiCar audiCar null; public CarContext(AudiCar audiCar) { this.audiCar audiCar; } public void orderCar(){ this.audiCar.makeCar(); }
} //客户----客户端这个客户是内行什么都懂他说我要A6销售部门立刻给他a6所以销售部门不用很懂
public class SimplyFactoryAndStrategy2 { public static void main(String[] args) throws IOException { //客户说我要什么什么样子的车子销售人员才知道他要什么样子的车子 AudiCar car new AudiA6(); car.setName(a6); CarContext context new CarContext(car); context.orderCar(); }
} //工厂模式---与上面的策略模式比较
//抽象产品
abstract class AudiCar{ private String name; public abstract void makeCar(); public String getName() { return name; } public void setName(String name) { this.name name; }
}
//具体产品
class AudiA6 extends AudiCar{ public void makeCar(){ System.out.println(this.getName()----go-----------------------); }
}
class AudiA4 extends AudiCar{ public void makeCar(){ System.out.println(this.getName()----go-----------------------); }
} //简单工厂---销售部门----服务端
class CarFactroy{ public static AudiCar createCar(String car){ AudiCar c null; if(A6.equalsIgnoreCase(car)) c new AudiA6(); else if(A4.equalsIgnoreCase(car)) c new AudiA4(); return c; }
} //客户----客户端这个客户是外行什么都不懂只要随便描述下车销售部门才能知道他要那款车所以销售部门比较牛
public class SimplyFactoryAndStrategy { public static void main(String[] args) throws IOException { System.out.print(请输入您要坐的车A6、A4); String carName new BufferedReader(new InputStreamReader(System.in)).readLine(); //客户说我要什么什么样子的车子销售人员才知道他要什么样子的车子 AudiCar car CarFactroy.createCar(carName); car.setName(carName); car.makeCar(); }
} 策略模式的优缺点 策略模式的主要优点有 策略类之间可以自由切换由于策略类实现自同一个抽象所以他们之间可以自由切换。易于扩展增加一个新的策略对策略模式来说非常容易基本上可以在不改变原有代码的基础上进行扩展。避免使用多重条件如果不使用策略模式对于所有的算法必须使用条件语句进行连接通过条件判断来决定使用哪一种算法在上一篇文章中我们已经提到使用多重条件判断是非常不容易维护的。 策略模式的缺点主要有两个 维护各个策略类会给开发带来额外开销可能大家在这方面都有经验一般来说策略类的数量超过5个就比较令人头疼了。必须对 客户端调用者暴露所有的策略类因为使用哪种策略是由客户端来决定的因此客户端应该知道有什么策略并且了解各种策略之间的区别否则后果很严 重。例如有一个排序算法的策略模式提供了快速排序、冒泡排序、选择排序这三种算法客户端在使用这些算法之前是不是先要明白这三种算法的适用情况 再比如客户端要使用一个容器有链表实现的也有数组实现的客户端是不是也要明白链表和数组有什么区别就这一点来说是有悖于迪米特法则的。 适用场景 做面向对象设计的对策略模式一定很熟悉因为它实质上就是面向对象中的继承和多态在看完策略模式的通用代码后我想即使之前从来没有听说过策略模式在开发过程中也一定使用过它吧至少在在以下两种情况下大家可以考虑使用策略模式 几个类的主要逻辑相同只在部分逻辑的算法和行为上稍有区别的情况。有几种相似的行为或者说算法客户端需要动态地决定使用哪一种那么可以使用策略模式将这些算法封装起来供客户端调用。 策略模式是一种简单常用的模式我们在进行开发的时候会经常有意无意地使用它一般来说策略模式不会单独使用跟模版方法模式、工厂模式等混合使用的情况比较多。 大粒度的 if --else if...可以使用 工厂策略模式搞定。