软件架构设计原则和工厂模式
这里写自定义目录标题
软件架构设计原则和工厂模式
软件架构设计原则
开闭原则
开闭原则(Open-Closed Principle, OCP)是指一个软件实体,如类、模块和函数应该对扩展开放,对修改关闭。
依赖倒置原则
依赖倒置原则(Dependence Inversion Principle, DIP)是指设计代码结构时,高层模块不应该依赖底层模块,二者都应该依赖其抽象。抽象不应该依赖细节;细节应该依赖抽象。通过依赖倒置,可以减少类与类之间的耦合性,提高系统稳定性,提高代码的可读性和可维护性,并能降低修改程序所造成的风险。
单一职责原则
单一职责(Simple Responsibility Principle, SRP)是指不要存在多于一个导致类变更的原因。假设我们有一个Class负责两个职责,一旦发生需求变更,修改其中一个职责的逻辑代码,有可能导致另一个发生故障。
接口隔离原则
接口隔离原则(Interface Segregation Principle,ISP)是指用多个专门的接口,而不使用单一的总接口,客户端不应该依赖它不需要的接口。这个原则指导我们在设计接口的时候应该注意以下几点
- 一个类对一类的依赖应该建立在最小的接口之上。
- 建立单一接口,不要建立庞大臃肿的接口
- 尽量细化接口,接口中的方法尽量少(不是越少越好,一定要适度)
接口隔离原则符合我们常说的高内聚低耦合的设计思想,从而使得类具有很好的可读性。
迪米特法则
迪米特原则(Law of Demeter,LOD)是指一个对象应该对其他对象保持最少的了解,又叫最少知道原则(Least Knowledge Principle,LKP),尽量降低类与类之间的耦合。迪米特原则主要强调只和朋友交流,不和陌生人说话。
里氏替换原则
里氏替换原则(Liskov Substitution Principle,LSP)是指如果对每一个类型为T1的对象o1,都有类型T2的对象o2,使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
可以理解为一个软件实体如果使用一个父类的话,那一定是适用于其子类,所有引用父类的地方必须能透明的使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。根据这个理解,我们总结一下:子类可以扩展分类的功能,但不能改变父类的功能。
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的入参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出)要比父类更严格或相等。
合成复用原则
合成复用原则(Composite/Aggregate Reuse Principle,CARP)是指尽量使用对象组合(has-a)/聚合(contains-a),而不是继承关系达到软件复用的目的。可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较少。
总结:学习设计原则,是学习设计模式的基础。在实际开发过程中,并不是一定要求所有代码都遵循设计原则,我们要考虑人力、世间、成本、质量,不是可以追求完美,要在适当的场景遵循设计原则,体现的是一种平衡取舍,帮助我们设计出更加优雅的代码结构。
工厂模式
简单工厂模式
这个没什么说的,直接上代码…
public interface BMW { void run(); } public class BMW320 implements BMW { @Override public void run() { System.out.println("BMW320 running"); } }` public class BMW520 implements BMW { @Override public void run() { System.out.println("BMW520 running"); } } public class BMWFactory { public static BMW createBMW(String type) { if("bmw320".equals(type)) { return new BMW320(); } else if("bmw520".equals(type)) { return new BMW520(); } else { throw new RuntimeException("没有这个类型"); } } } public static void main(String[] args) { BMW bmw320 = BMWFactory.createBMW("bmw320"); bmw320.run(); BMW bmw520 = BMWFactory.createBMW("bmw520"); bmw520.run(); }
首先,我们创建了宝马系列的产品,然后由宝马工厂生产你需要的产品。获取的方式是,你先告诉宝马产商,你需要宝马的那个产品,然后工厂会创建一个你需要的产品。
这种设计模式的缺点是:不符合开闭原则,每当新增一个产品,我们都需要去修改现有的代码,不利于扩展。
优点:只需传入一个参数,就可以获取你需要的对象,不需要知道对象创建的细节。
我们可以通过修改入参,来改善这个问题。
1.把入参改成包名+类名,然后通过反射来创建对象(需要强转)
2.直接传入一个class 对象,通过反射创建对象
简单工厂模式在JDK源码中的应用,例如Calendar.getInstance(),进入getInstance()方法后我们可以看到内部实现用的其实也是简单工厂
private static Calendar createCalendar(TimeZone zone, Locale aLocale) { CalendarProvider provider = LocaleProviderAdapter.getAdapter(CalendarProvider.class, aLocale) .getCalendarProvider(); if (provider != null) { try { return provider.getInstance(zone, aLocale); } catch (IllegalArgumentException iae) { // fall back to the default instantiation } } Calendar cal = null; if (aLocale.hasExtensions()) { String caltype = aLocale.getUnicodeLocaleType("ca"); if (caltype != null) { switch (caltype) { case "buddhist": cal = new BuddhistCalendar(zone, aLocale); break; case "japanese": cal = new JapaneseImperialCalendar(zone, aLocale); break; case "gregory": cal = new GregorianCalendar(zone, aLocale); break; } } } if (cal == null) { // If no known calendar type is explicitly specified, // perform the traditional way to create a Calendar: // create a BuddhistCalendar for th_TH locale, // a JapaneseImperialCalendar for ja_JP_JP locale, or // a GregorianCalendar for any other locales. // NOTE: The language, country and variant strings are interned. if (aLocale.getLanguage() == "th" && aLocale.getCountry() == "TH") { cal = new BuddhistCalendar(zone, aLocale); } else if (aLocale.getVariant() == "JP" && aLocale.getLanguage() == "ja" && aLocale.getCountry() == "JP") { cal = new JapaneseImperialCalendar(zone, aLocale); } else { cal = new GregorianCalendar(zone, aLocale); } } return cal; }
工厂方法模式
工厂方法模式(Factory Method Pattern)是指定义一个创建对象的接口,但让实现这个接口的类来决定实例化那个类,工厂方法让类的实例化推迟到子类中进行。
把上面的代码修改下:
public interface IFactory { BMW createBMW(); }
public class BMW320Factory implements IFactory { @Override public BMW createBMW() { return new BMW320(); } }
public class BMW520Factory implements IFactory { @Override public BMW createBMW() { return new BMW520(); } }
测试代码:
public class Test { public static void main(String[] args) { IFactory bmw320Factory = new BMW320Factory(); BMW bmw320 = bmw320Factory.createBMW(); bmw320.run(); IFactory bmw520Factory = new BMW320Factory(); BMW bmw520 = bmw520Factory.createBMW(); bmw520.run(); } }
类图:
Logback中的工厂模式就是使用的这种,这里就不细说了。
工厂方法适用于以下场景:
- 创建对象需要大量的重复代码
- 客户端不依赖于产品类实例如何被创建、实现等细节
- 一个类通过其子类来指定创建哪个对象
优点:符合开闭原则,易于扩展
缺点:类的个数容易过多,增加复杂度。增加了系统的抽象性和理解难度
抽象工厂模式
抽象工厂模式(Abstract Factory Pattern)是指提供一个创建一系列相关或相互依赖对象的接口,无须指定他们具体的类。在讲解抽象工厂之前,我们需要了解两个概念,产品等级结构和产品族,看下面的图:
从上图中看出有正方形,圆形和菱形三种图形,相同颜色深浅的就代表同一个产品族,相同形状的代表同一个产品等级结构。同样可以从生活中来举例,比如,美的电器生产多种家用电器。那么上图中,颜色最深的正方形就代表美的洗衣机、颜色最深的圆形代表美的空调、颜色最深的菱形代表美的热水器,颜色最深的一排都属于美的品牌,都是美的电器这个产品族。再看最右侧的菱形,颜色最深的我们指定了代表美的热水器,那么第二排颜色稍微浅一点的菱形,代表海信的热水器。同理,同一产品结构下还有格力热水器,格力空调,格力洗衣机。
接下来我们看下代码实现:
/** * 空调 */ public interface AirConditioning { void refrigeration(); }
/** * 洗衣机 */ public interface WashingMachine { void wash(); }
/** * 热水器 */ public interface WaterHeater { void boilWater(); }
public class HisenseAirConditioning implements AirConditioning { @Override public void refrigeration() { System.out.println("海信空调制冷"); } }
public class HisenseWashingMachine implements WashingMachine { @Override public void wash() { System.out.println("海信洗衣机洗衣"); } }
public class HisenseWaterHeater implements WaterHeater { @Override public void boilWater() { System.out.println("海信热水器热水"); } }
public class MideaAirConditioning implements AirConditioning { @Override public void refrigeration() { System.out.println("美的空调制冷"); } }
public class MideaWashingMachine implements WashingMachine { @Override public void wash() { System.out.println("美的洗衣机洗衣服"); } }
public class MideaWaterHeater implements WaterHeater { @Override public void boilWater() { System.out.println("美的热水器热水"); } }
/** * 电器工厂 */ public interface ElectricalApplianceFactory { /** * 创建热水器 * @return */ WaterHeater createWaterHeater(); /** * 创建空调 * @return */ AirConditioning createAirConditioning(); /** * 创建洗衣机 * @return */ WashingMachine createWashingMachine(); }
public class HisenseFactory implements ElectricalApplianceFactory { @Override public WaterHeater createWaterHeater() { return new HisenseWaterHeater(); } @Override public AirConditioning createAirConditioning() { return new HisenseAirConditioning(); } @Override public WashingMachine createWashingMachine() { return new HisenseWashingMachine(); } }
public class HisenseFactory implements ElectricalApplianceFactory { @Override public WaterHeater createWaterHeater() { return new HisenseWaterHeater(); } @Override public AirConditioning createAirConditioning() { return new HisenseAirConditioning(); } @Override public WashingMachine createWashingMachine() { return new HisenseWashingMachine(); } }
public class Test { public static void main(String[] args) { ElectricalApplianceFactory electricalApplianceFactory = new HisenseFactory(); AirConditioning airConditioning = electricalApplianceFactory.createAirConditioning(); airConditioning.refrigeration(); WashingMachine washingMachine = electricalApplianceFactory.createWashingMachine(); washingMachine.wash(); WaterHeater waterHeater = electricalApplianceFactory.createWaterHeater(); waterHeater.boilWater(); electricalApplianceFactory = new MideaFactory(); WaterHeater waterHeater1 = electricalApplianceFactory.createWaterHeater(); waterHeater1.boilWater(); WashingMachine washingMachine1 = electricalApplianceFactory.createWashingMachine(); washingMachine1.wash(); AirConditioning airConditioning1 = electricalApplianceFactory.createAirConditioning(); airConditioning1.refrigeration(); } }
上面代码描述了三个产品族热水器、空调和洗衣机,也描述了两个产品等级美的和海信。抽象工厂可以清晰的描述这样的一层复杂的关系。但是如果后期还要加产品,比如说冰箱,那么我们从抽象工厂到具体的工厂全部都要调整,不符合开闭原则。所以它也是有缺点的:
- 扩展困难,需要修改抽象工厂的接口
- 增加了系统的抽象和理解难度。
- 点赞
- 收藏
- 分享
- 文章举报
- 设计模式(工厂方法)与软件开发原则
- 软件的架构与设计模式之层次原则
- 软件的架构与设计模式:层次原则
- 软件架构设计原则和模式(上):分层架构设计
- 软件的架构与设计模式之层次原则
- 设计模式与软件架构设计
- 《.NET应用架构设计:原则、模式与实践》新书博客--试读-1.1.3 架构设计的优点...
- [设计模式]-架构中的设计原则(笔记ing)
- 连载16:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)
- 软件的架构与设计模式之模式的种类
- 连载32:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)
- 连载35:软件体系设计新方向:数学抽象、设计模式、系统架构与方案设计(简化版)(袁晓河著)
- Java设计模式(一)设计模式的原则、工厂方法和抽象工厂
- 移动架构25_设计模式六大原则三:接口隔离原则
- 一起谈.NET技术,走向ASP.NET架构设计——第五章:业务层模式,原则,实践(前篇)
- CSA: 软件的架构与设计模式之什么是架构
- 软件架构和设计模式
- 架构设计的几个痛点_我总结出的架构原则和模式
- 软件的架构与设计模式:Layers模式
- 软件架构设计的七大原则