抽象工厂-模式设计
简说设计模式——抽象工厂模式

简说设计模式——抽象⼯⼚模式⼀、什么是抽象⼯⼚模式抽象⼯⼚模式其实就是多个,⽐如前⾯⼯⼚⽅法模式中,我们创建多个不同类型的数据库,有MySQL、SQLServer等等,就是⽤⼯⼚⽅法模式来实现的,但此时我们只能实现⼀个表(具体内容见下⽅⼯⼚模式的实现),我们数据库中当然不可能只有⼀个表呀,所以抽象⼯⼚模式就来了。
抽象⼯⼚模式(Abstract Factory),提供⼀个创建⼀系列相关或相互依赖对象的接⼝,⽽⽆需指定它们具体的类。
UML结构图如下:其中,AbstractFactory是抽象⼯⼚接⼝,⾥⾯包含所有的产品创建的抽象⽅法;ConcreteFactory则是具体的⼯⼚,创建具有特定实现的产品对象;AbstractProduct是抽象产品,有可能由两种不同的实现;ConcreteProduct则是对于抽象产品的具体分类的实现。
抽象⼯⼚模式是⼯⼚⽅法模式的升级版本,在有多个业务品种、业务分类时,通过抽象⼯⼚模式产⽣需要的对象是⼀种⾮常好的解决⽅式。
下⾯是抽象⼯⼚模式的通⽤源代码类图:1. AbstractFactory类下述代码是⼀个抽象⼯⼚类,它的职责是定义每个⼯⼚要实现的功能,有n个产品族,在抽象⼯⼚类中就应该有n个创建⽅法。
这⾥按上述类图,给出A、B两个产品族,即构造两个⽅法。
1public abstract class AbstractFactory {23//创建A产品家族4public abstract AbstractProductA createProductA();5//创建B产品家族6public abstract AbstractProductB createProductB();78 }2. AbstractProduct类抽象产品类,两个抽象产品类可以有关系,例如共同继承或实现⼀个抽象类或接⼝。
这⾥给出A产品的抽象类,产品类B类似,不再赘述。
1public abstract class AbstractProductA {23//每个产品共有的⽅法4public void shareMethod() {}5//每个产品相同⽅法,不同实现6public abstract void doSomething();78 }3. ConcreteFactory类具体⼯⼚实现类,如何创建⼀个产品是由具体的实现类来完成的。
抽象工厂模式(一)

抽象工厂模式(一)抽象工厂模式(Abstract Factory Pattern)是一种对象创建型设计模式,属于工厂模式的扩展版。
它通过定义一个抽象工厂来统一创建一系列相关或相互依赖的对象,而这些对象之间具有一定的约束关系,即它们属于同一个产品族。
抽象工厂模式的实现过程中,需要定义抽象工厂类和具体工厂类以及抽象产品类和具体产品类。
具体工厂类实现抽象工厂类的所有抽象方法,用于创建同一产品族的不同具体产品,同时具体产品类继承自抽象产品类,用于定义一类产品的共性和差异性。
抽象工厂模式的实现具有以下几个优点:1. 隐藏对象创建过程:抽象工厂模式可以将对象的创建过程隐藏起来,并且只需要使用工厂类即可创建所有相互依赖的对象,因此可以降低系统中对象的耦合度。
2. 提供一个封装的工厂接口:抽象工厂模式提供一个工厂接口用于创建产品族,客户端通过使用这个接口来创建需要的产品,而无需关心产品的具体实现。
3. 简化了使用者的代码:抽象工厂模式可以将对象的创建和使用分离开来,避免了一系列的对象创建和初始化的问题,并且能够简化使用者的代码。
4. 具有良好的扩展性:由于抽象工厂模式通过抽象接口提供统一的工厂方法,因此可以方便地增加新的产品族和产品等扩展功能。
5. 符合开闭原则:抽象工厂模式对扩展开放,对修改封闭,因此它符合开闭原则的要求。
在使用抽象工厂模式时,有一些需要注意的地方:1. 需要考虑产品族的扩展问题:抽象工厂模式一般用于创建一系列相关的产品,如果需要增加新的产品族,需要修改抽象工厂接口和所有的实现类,因此需要考虑到产品族扩展的问题。
2. 可能会增加系统的复杂度:使用抽象工厂模式可能会增加代码的复杂度,因为需要创建一系列的抽象类和实现类,但这也是保证抽象工厂模式功能强大的原因。
3. 需要考虑产品等级的问题:抽象工厂模式适用于创建一系列相关或相互依赖的对象,如果要创建多个产品等级结构的对象,可能需要使用其他的设计模式。
简单工厂模式、工厂模式和抽象工厂模式区别及优缺点

简单⼯⼚模式、⼯⼚模式和抽象⼯⼚模式区别及优缺点各位⼩伙伴好,今天给⼤家主要介绍⼀下简单⼯⼚模式、⼯⼚模式和抽象⼯⼚模式的区别及各⾃的优缺点。
(本⽂实现语⾔为Python3)【前⾔】众所周知今天所讲的内容是设计模式的⼀类;对于设计模式这个概念,我想⾸先请⼤家问问⾃⼰:1、什么是设计模式 2、我们为什么要了解并学习设计模式?从我上学的时候我相信⼤家跟我⼀样也接触过设计模式的课程,当时可能懵懵懂懂只是知其然,当时还会想明明可以直接写出来为什么要搞成这样的形式,我就算学会了它到底什么时候能⽤呢?⼀系列的问题...Emm算了到时候再想想(lazy)。
随着实践的不断增多,现在我想可以对这些问题有个初步的回答了: 1、在我看来,设计模式外在看是经过前⼈不断实践总结出的针对某些指定场景极其好⽤的⼀种代码结构设计模板;内在看其实是⼀种设计思想(即为什么他们会这么想,这样想较之其他⽅法有什么好处)。
当我们真正的理解设计思想的时候,就可能会在⾯对问题和场景时⾃然⽽然的灵活运⽤到多种设计模式,⽽不是单⼀的刻板结构。
2、在⼯程化的开发中,需求往往是会不断变化的,这也是让很多开发⼈员及其烦躁的地⽅,所以才会有开发与产品的亲密关系。
设计模式就是为了抵御外部需求变化产⽣的。
设计模式应符合开闭原则(类、模块和函数等应该对扩展开放,对修改关闭。
)⼀个好的设计在之后的开发中,包括发⽣重⼤需求变化的时候,往往代码只需要进⾏简单重构去进⾏适配,⽽不是通过打补丁的⽅式去堆砌,也很容易避免破窗效应,充分的发挥了灵活的扩展和适配,⼤⼤增强了维护性。
综上所述,我们了解并学习设计模式,可以使我们的代码变得更加健壮、结构清晰,可以从容、灵活的适配需求变更(可复⽤、可扩展、可维护、够灵活)【正⽂】⾸先,这三种模式解决的问题是实例化对象的问题;那么为什么不直接实例化⽽⽤这样的⼯⼚形式去实例化对象呢?因为【待实例化对象太多(⼦类多且变动、调⽤频繁)或者实例化对象的过程、准备⽐较复杂】,直接实例化意味着每次都⽤重复的去执⾏实例化这个操作,如果有很多待实例化的操作,那么就要重复执⾏很多次,更不要说万⼀在实例化之前还要执⾏⼀堆配置项的初始化。
工厂模式之抽象工厂

⼯⼚模式之抽象⼯⼚主要参考《⼤话设计模式》1. 引⼊ 前⾯介绍的⼯⼚⽅法模式中考虑的是⼀类产品的⽣产,如畜牧场养动物、电视机⼚⽣产电视等,然⽽,现实⽣活中,许多⼯⼚是综合型⼯⼚,能够⽣产各类产品,如⼤学包括各个系。
2. 定义 抽象⼯⼚模式,为创建⼀组相关或相互依赖的对象提供⼀个接⼝,且⽆需指定它们的具体类。
是所有形态的⼯⼚模式中最为抽象和最具⼀般性的⼀种形态。
3. 场景实现3.1 场景描述 在框架开发中,对于同⼀个ORM,假如刚开始开发时使⽤SQL Server数据库,但是也希望能够连接Access数据库,或其他的数据库(如MySql、Oracle等)。
SQL Server在.net中使⽤的System.Data.SqlClient命名空间下的SqlConnection、SqlCommand、SqlParameter、SqlDataReader、SqlDataAdapter,⽽Access要⽤System.Data.Olede命名空间下的相应对象,我们不可能修改命名空间,或者重新写相同的业务代码只是修改与数据库相关的代码,这就是两倍的⼯作量。
因⽽,针对类似问题,可以采⽤抽象⼯⼚模式解决。
⽐如,现在要在业务逻辑代码相似的情况下,将SqlServer数据库改为使⽤Access数据库。
以“新增⽤户”和“获取⽤户”为例给出最基本的数据库访问程序。
3.2 最基本的数据访问程序 class User{private int _id;public int ID{get { return _id;}set { _id = value; }}private string _name;public string Name{get { return _name; }set { _name = value; }}} class SqlServer{public void insert(User user){Console.WriteLine("在sqlserver中为User表添加⼀条记录");}public void select(int id){Console.WriteLine("在sqlserver中根据⽤户id查找⽤户");}} static void Main(string[] args){User user = new User();SqlServer sql = new SqlServer();sql.insert(user);sql.select(1);Console.Read();}运⾏结果如下: 上述实现中,⽆法灵活的把sqlserver数据库替换成其他数据库,原因就是SqlServer sql = new SqlServer()使得sql对象被框死在Sqlserver上,如果此处是灵活的(多态的)应⽤,在执⾏sql.insert(user)时,不需要关注数据库到底是sqlserver还是access,因此,我们可以采⽤⼯⼚⽅法模式进⾏封装。
抽象工厂设计模式

抽象工厂(Abstract Factory)设计模式目的:提供一个创建一系列相关或相互依赖对象的接口,无需指定它们具体的类。
别名:Kit“抽象”来自“抽象产品角色”,而“抽象工厂”就是“抽象产品角色的工厂”。
在简单工厂中,我们的工厂类一次只可以处理一类产品。
那么如果我们想处理多类产品,简单工厂是满足不了的,必须要用抽象工厂设计模式。
抽象工厂模式是所有形态的工厂模式中最为抽象和最具一般性的一种形态。
抽象工厂模式是指当有多个抽象角色时,使用的一种工厂模式。
抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定具体产品类型的情况下,创建多个产品族中的对象。
当每个抽象产品都有多于一个的具体子类的时候,工厂角色怎么知道实例化哪一个子类呢?比如每个抽象产品角色都有两个具体产品。
抽象工厂模式提供两个具体工厂角色,分别对应于这两个具体产品角色,每一个具体工厂角色只负责某一个产品角色的实例化。
每一个具体工厂类只负责创建抽象产品的某一个具体子类的实例。
每一个模式都是针对一定问题的解决方案,工厂方法模式针对的是一个产品等级结构;而抽象工厂模式针对的是多个产品等级结构。
成分:从上图可以看出,抽象工厂模式涉及到以下几类角色:1. 抽象工厂(AbstractFactory)角色:声明一个创建抽象产品对象的操作接口。
担任这个角色的是工厂方法模式的核心,它是与应用系统的商业逻辑无关的。
通常使用Java 接口或者抽象Java 类实现,而所有的具体工厂类必须实现这个Java 接口或继承这个抽象Java 类。
2. 实体工厂类(Conrete Factory)角色:这个角色直接在客户端的调用下实现创建具体产品对象的操作。
这个角色含有选择合适的产品对象的逻辑,而这个逻辑是与应用系统的商业逻辑紧密相关的。
通常使用具体Java 类实现这个角色。
3. 抽象产品(Abstract Product)角色:为一类产品对象声明一个接口。
担任这个角色的类是工厂方法模式所创建的对象的父类,或它们共同拥有的接口。
抽象工厂模式介绍

抽象工厂模式介绍抽象工厂模式是一种软件设计模式,它提供了一种创建一系列相互关联或依赖的对象的方法,而无需指定具体实现类。
该模式的核心思想是将对象的创建和使用分离,从而在系统设计中提供更高的灵活性和可扩展性。
抽象工厂模式基于工厂方法模式,它将工厂抽象化,允许客户端使用抽象工厂来创建一系列相关或依赖的对象,而不必关心具体的实现类。
通过使用抽象工厂模式,我们可以使系统更易于扩展和修改,满足不同的需求和变化。
抽象工厂模式的结构包括抽象工厂、具体工厂、抽象产品和具体产品。
抽象工厂定义了创建一系列相关或依赖对象的方法,具体工厂实现了这些方法。
抽象产品定义了一系列相关产品的接口,具体产品实现了这些接口。
通过抽象工厂和具体产品的组合,我们可以创建一系列具有关联性的对象。
抽象工厂模式的使用可以带来多种好处。
首先,它可以提供系统的灵活性。
由于抽象工厂将对象的创建和使用分离,我们可以很容易地替换具体的工厂实现,从而满足不同的需求和变化。
其次,它可以提供系统的可扩展性。
通过增加新的具体工厂和产品实现,我们可以方便地扩展系统的功能。
再次,它可以提供系统的可维护性。
由于抽象工厂模式将创建对象的代码集中于一个工厂类中,我们可以更容易地维护和修改代码。
最后,它可以提供系统的解耦性。
客户端只需要与抽象工厂和抽象产品进行交互,不需要了解具体产品的实现细节,从而降低了系统的耦合度。
抽象工厂模式的应用场景较为广泛。
一种常见的应用场景是在需要创建一系列相互依赖的对象的时候。
比如,在一个图形界面应用程序中,需要创建一系列按钮和文本框,它们都依赖于同一个主题。
通过使用抽象工厂模式,我们可以创建具有相同主题的按钮和文本框,保持它们的外观风格一致。
另一个应用场景是在需要创建一系列相关产品族的时候。
比如,在一个汽车制造系统中,需要生产不同品牌和型号的汽车,每个品牌和型号都由相应的零部件组成。
通过使用抽象工厂模式,我们可以为每个品牌和型号创建对应的汽车工厂和零部件工厂,从而保证汽车的组装作业能够顺利进行。
【设计模式-工厂模式】男男女女的抽象工厂模式

【设计模式-⼯⼚模式】男男⼥⼥的抽象⼯⼚模式背景虽然⼥娲已经成功将⼈类创造出来了,可是都是没有性别的,那么后续该如何繁衍呢。
为此,除了增加⼈种外,我们还需要增加所有⼈类都有的⼀个属性:性别。
由此:⼈种和性别相互组合⽣成6中不同的⼈类男⿊⼈、⼥⿊⼈、男⽩⼈、⼥⽩⼈、男黄⼈、⼥黄⼈原来的⼀个⼋卦炉也需要进⾏修改,变为专门⽣产男性的"男⼋卦炉" 和专门⽣产⼥性的 “⼥⼋卦炉”类图可以看到我们在原有的⼏个⼈种上,⼜重新继承并实现了两个类,分别⽤于表⽰不同⼈种的男⼥特别说明的是HumanFactory接⼝,在这个接⼝中定义了三个⽅法,分别⽤于⽣产不同的肤⾊的⼈种,也就是我们将肤⾊作为Y轴,性别作为X轴,通过X坐标和Y坐标唯⼀确定⼀个⽣产出来的对象。
代码⼈种接⼝public interface Human {//每个⼈种的⽪肤都是不同的颜⾊public void getColor();//每个⼈类都会发声public void talk();public void getSex();}⼈种接⼝即抽象产品,该产品的共同属性定义:肤⾊和语⾔,⽽性别则是不同产品下更深层的细分实现⼈种接⼝的黄种⼈public abstract class AbstractYellowHuman implements Human{@Overridepublic void getColor() {System.out.println("黄种⼈");}@Overridepublic void talk() {System.out.println("国语");}}继承了该接⼝的抽象黄种⼈类,每个抽象类都会实现产品的公共细节,⽽每个抽象类的都会有两个实现类,分别实现各⾃的不同的细节:性别黄种⼈⼥性public class YellowWoman extends AbstractYellowHuman{@Overridepublic void getSex() {System.out.println("YellowWoman");}}⼋卦炉/*** 产品类* 有N个产品组,在抽象⼯⼚类中就应该有N个创建⽅法;* 每个产品有M个产品扩展维度就应该有M个产品实现⼯⼚类,* 在每个实现⼯⼚中,实现不同的产品族的⽣产任务.* @author LiPeng01* @since 2020/8/8 7:31 下午*/public interface HumanFactory {public Human doYellowHuman();public Human doWhiteHuman();public Human doBlackHuman();}在接⼝中我们可以看到 抽象的⼯⼚是可以⽣产出不同肤⾊的⼈种的。
第6章抽象工厂模式

第6章抽象工厂模式抽象工厂模式是一种创建型设计模式,旨在提供一个创建一系列相关或相互依赖对象的接口,而无需指定具体的类。
通过使用抽象工厂模式,可以使客户端与具体实例的创建分离,降低了客户端与具体实例之间的耦合度。
本文将详细介绍抽象工厂模式的定义、结构、应用场景以及优缺点。
一、定义抽象工厂模式,也称为Kit模式,是一种对象创建型模式。
它提供一个接口,用于创建一系列具有共同接口的相关或相互依赖的对象,而无需指定其具体实现类。
二、结构抽象工厂模式包含以下几个角色:1. 抽象工厂(Abstract Factory):定义了创建产品对象的接口,它包含了一组创建产品的方法。
2. 具体工厂(Concrete Factory):实现了抽象工厂中的方法,完成具体产品的创建。
3. 抽象产品(Abstract Product):定义了产品的接口,是具体产品类的父类。
4. 具体产品(Concrete Product):实现了抽象产品接口的具体产品类。
三、应用场景抽象工厂模式通常在以下几种情况下使用:1.系统需要一系列相关或相互依赖的对象,并且不希望客户端与具体实例之间有耦合。
2.客户端不应知道所使用的具体工厂和具体产品类的名称。
3.系统需要提供一种产品的多种实现,用户可以选择使用哪个实现。
四、优缺点抽象工厂模式具有以下优点:1.将具体产品的创建与使用解耦,客户端只需要知道使用抽象工厂即可。
2.通过切换具体工厂,可以改变系统的配置,实现不同产品簇的切换。
3.新增具体工厂和具体产品类只需实现对应的接口,符合开闭原则。
抽象工厂模式的缺点是:1.当产品簇需要新增产品时,需要修改所有的具体工厂类,不符合开闭原则。
2.当具体产品较多时,会导致具体工厂类的数量增加,难以管理。
五、代码示例我们以汽车和轮胎为例,介绍抽象工厂模式的代码实现。
首先,定义抽象工厂和抽象产品的接口:```java//抽象工厂public interface AbstractFactoryCar createCar(;Tire createTire(;//抽象产品public interface Carvoid drive(;//抽象产品public interface Tirevoid rotate(;```然后,实现具体工厂和具体产品的类:```java//具体工厂public class DomesticFactory implements AbstractFactory public Car createCareturn new DomesticCar(;}public Tire createTirreturn new DomesticTire(;}//具体工厂public class ForeignFactory implements AbstractFactory public Car createCareturn new ForeignCar(;}public Tire createTirreturn new ForeignTire(;}//具体产品public class DomesticCar implements Carpublic void drivSystem.out.println("国产汽车开始启动");}//具体产品public class ForeignCar implements Carpublic void drivSystem.out.println("进口汽车开始启动");}//具体产品public class DomesticTire implements Tire public void rotatSystem.out.println("国产轮胎开始旋转");}//具体产品public class ForeignTire implements Tirepublic void rotatSystem.out.println("进口轮胎开始旋转");}```最后,客户端通过具体工厂创建具体产品:```javapublic class Clientpublic static void main(String[] args) AbstractFactory factory = new DomesticFactory(; Car car = factory.createCar(;car.drive(;Tire tire = factory.createTire(;tire.rotate(;factory = new ForeignFactory(;car = factory.createCar(;car.drive(;tire = factory.createTire(;tire.rotate(;}```运行客户端代码输出:```国产汽车开始启动国产轮胎开始旋转进口汽车开始启动进口轮胎开始旋转```通过抽象工厂模式,客户端代码无需关注具体的产品类,只需要通过工厂创建产品即可。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
•概述在软件系统中,经常面临着“一系列相互依赖的对象”的创建工作;同时由于需求的变化,往往存在着更多系列对象的创建工作。
怎么应对这种变化?怎么绕过常规的对象的创建方法(new),提供一种“封装机制”来避免客户程式和这种“多系列具体对象创建工作”的紧耦合?这就是我们要说的抽象工厂模式。
意图提供一个创建一系列相关或相互依赖对象的接口,而无需指定他们具体的类。
模型图逻辑模型:物理模型:生活中的例子抽象工厂的目的是要提供一个创建一系列相关或相互依赖对象的接口,而不必指定他们具体的类。
这种模式能汽车制造厂所使用的金属冲压设备中找到。
这种冲压设备能制造汽车车身部件。
同样的机械用于冲压不同的车型的右边车门、左边车门、右前挡泥板、左前挡泥板和引擎罩等等。
通过使用转轮来改动冲压盘,这个机械产生的具体类能在三分钟内改动。
抽象工厂之新解虚拟案例中国企业需要一项简单的财务计算:每月月底,财务人员要计算员工的工资。
员工的工资= (基本工资+ 奖金- 个人所得税)。
这是个放之四海皆准的运算法则。
为了简化系统,我们假设员工基本工资总是4000美金。
中国企业奖金和个人所得税的计算规则是:奖金= 基本工资(4000) * 10%个人所得税= (基本工资+ 奖金) * 40%我们目前要为此构建一个软件系统(代号叫Softo),满足中国企业的需求。
案例分析奖金(Bonus)、个人所得税(Tax)的计算是Softo系统的业务规则(Service)。
工资的计算(Calculator)则调用业务规则(Service)来计算员工的实际工资。
工资的计算作为业务规则的前端(或客户端Client)将提供给最终使用该系统的用户(财务人员)使用。
针对中国企业为系统建模根据上面的分析,为Softo系统建模如下:则业务规则Service类的代码如下:1using System;23namespace ChineseSalary4{5 /**//// <summary>6 /// 公用的常量7 /// </summary>8 public class Constant9 {10 public static double BASE_SALARY = 4000;11 }12}1using System;23namespace ChineseSalary4{5 /**//// <summary>6 /// 计算中国个人奖金7 /// </summary>8 public class ChineseBonus9 {10 public double Calculate()11 {12 return Constant.BASE_SALARY * 0.1;13 }14 }15}16客户端的调用代码:1using System;23namespace ChineseSalary4{5 /**//// <summary>6 /// 计算中国个人所得税7 /// </summary>8 public class ChineseTax9 {10 public double Calculate()11 {12 return (Constant.BASE_SALARY + (Constant.BASE_SALARY * 0.1)) * 0.4;13 }14 }15}16运行程式,输入的结果如下:Chinese Salary is:2640针对美国企业为系统建模为了拓展国际市场,我们要把该系统移植给美国公司使用。
美国企业的工资计算同样是: 员工的工资= 基本工资+ 奖金-个人所得税。
不过他们的奖金和个人所得税的计算规则不同于中国企业:美国企业奖金和个人所得税的计算规则是:奖金= 基本工资* 15 %个人所得税= (基本工资* 5% + 奖金* 25%)根据前面为中国企业建模经验,我们仅仅将ChineseTax、ChineseBonus修改为AmericanTax、AmericanBonus。
修改后的模型如下:则业务规则Service类的代码如下:1using System;23namespace AmericanSalary4{5 /**//// <summary>6 /// 公用的常量7 /// </summary>8 public class Constant9 {10 public static double BASE_SALARY = 4000;11 }12}131using System;23namespace AmericanSalary4{5 /**//// <summary>6 /// 计算美国个人奖金7 /// </summary>8 public class AmericanBonus9 {10 public double Calculate()11 {12 return Constant.BASE_SALARY * 0.1;13 }14 }15}161using System;23namespace AmericanSalary4{5 /**//// <summary>6 /// 计算美国个人所得税7 /// </summary>8 public class AmericanTax9 {10 public double Calculate()11 {12 return (Constant.BASE_SALARY + (Constant.BASE_SALARY * 0.1)) * 0.4;13 }14 }15}16客户端的调用代码:12using System;34namespace AmericanSalary5{6 /**//// <summary>7 /// 客户端程式调用8 /// </summary>9 public class Calculator10 {11 public static void Main(string[] args)12 {13 AmericanBonus bonus = new AmericanBonus();14 double bonusValue = bonus.Calculate();1516 AmericanTax tax = new AmericanTax();17 double taxValue = tax.Calculate();1819 double salary = 4000 + bonusValue - taxValue;2021 Console.WriteLine("American Salary is:" + salary);22 Console.ReadLine();23 }24 }25}26运行程式,输入的结果如下:American Salary is:2640整合成通用系统让我们回顾一下该系统的发展历程:最初,我们只考虑将Softo系统运行于中国企业。
但随着MaxDO公司业务向海外拓展,MaxDO需要将该系统移植给美国使用。
移植时,MaxDO不得不抛弃中国企业的业务规则类ChineseTax和ChineseBonus,然后为美国企业新建两个业务规则类: AmericanTax,AmericanBonus。
最后修改了业务规则调用Calculator类。
结果我们发现:每当Softo系统移植的时候,就抛弃原来的类。
目前,如果中国联想集团要购买该系统,我们不得不再次抛弃AmericanTax,AmericanBonus,修改回原来的业务规则。
一个能即时想到的做法就是在系统中保留所有业务规则模型,即保留中国和美国企业工资运算规则。
通过保留中国企业和美国企业的业务规则模型,如果该系统在美国企业和中国企业之间转换时,我们仅仅需要修改Caculator 类即可。
让移植工作更简单前面系统的整合问题在于:当系统在客户在美国和中国企业间转换时仍然需要修改Caculator代码。
一个维护性良好的系统应该遵循“开闭原则”。
即:封闭对原来代码的修改,开放对原来代码的扩展(如类的继承,接口的实现)我们发现不论是中国企业还是美国企业,他们的业务运规则都采用同样的计算接口。
于是非常自然地想到建立两个业务接口类Tax,Bonus,然后让AmericanTax、AmericanBonus和ChineseTax、ChineseBonus分别实现这两个接口,据此修正后的模型如下:此时客户端代码如下:12using System;34namespace InterfaceSalary5{6 /**//// <summary>7 /// 客户端程式调用8 /// </summary>9 public class Calculator10 {11 public static void Main(string[] args)12 {13 Bonus bonus = new ChineseBonus();14 double bonusValue = bonus.Calculate();1516 Tax tax = new ChineseTax();17 double taxValue = tax.Calculate();1819 double salary = 4000 + bonusValue - taxValue;2021 Console.WriteLine("Chinaese Salary is:" + salary);22 Console.ReadLine();23 }24 }25}26为业务规则增加工厂方法然而,上面增加的接口几乎没有解决所有问题,因为当系统的客户在美国和中国企业间转换时Caculator代码仍然需要修改。
只不过修改少了两处,不过仍然需要修改ChineseBonus,ChineseTax部分。
致命的问题是:我们需要将这个移植工作转包给一个叫Hippo的软件公司。
由于版权问题,我们并未提供Softo系统的源码给Hippo公司,因此Hippo公司根本无法修改Calculator,导致实际上移植工作无法进行。
为此,我们考虑增加一个工具类(命名为Factory),代码如下:1using System;23namespace FactorySalary4{5 /**//// <summary>6 /// Factory类7 /// </summary>8 public class Factory9 {10 public Tax CreateTax()11 {12 return new ChineseTax();13 }1415 public Bonus CreateBonus()16 {17 return new ChineseBonus();18 }19 }20}21修改后的客户端代码:12using System;34namespace FactorySalary5{6 /**//// <summary>7 /// 客户端程式调用8 /// </summary>9 public class Calculator10 {11 public static void Main(string[] args)12 {13 Bonus bonus = new Factory().CreateBonus();14 double bonusValue = bonus.Calculate();1516 Tax tax = new Factory().CreateTax();17 double taxValue = tax.Calculate();1819 double salary = 4000 + bonusValue - taxValue;2021 Console.WriteLine("Chinaese Salary is:" + salary);22 Console.ReadLine();23 }24 }25}26不错,我们解决了一个大问题,设想一下:当该系统从中国企业移植到美国企业时,我们目前需要做什么?答案是: 对于Caculator类我们什么也不用做。