设计/开发模式 理解
多态可以用接口实现
代码复用可以用组合+委托来实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public interface Flyable { void fly (); } public class FlyAbility implements Flyable { @ Override public void fly () { //... } } // 省略下单和叫 类似的代码 public class Ostrich implements Tweetable , EggLayable { // 鸵鸟 private TweetAbility tweetAbility = new TweetAbility (); // 组合 private EggLayAbility eggLayAbility = new EggLayAbility (); // 组合 //... 省略其他属性和方法... @ Override public void tweet () { tweetAbility . tweet (); // 委托 } @ Override public void layEgg () { eggLayAbility . layEgg (); // 委托 } } |
工厂模式
用途,创建不同但是相关类型的对象
何时用工厂模式:
1、创建过程涉及复杂的 if-else 分支判断
2、对象创建需要组装多个其他类对象或者需要复杂的初始化过程
简单工厂:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | public class RuleConfigSource { public RuleConfig load ( String ruleConfigFilePath ) { IRuleConfigParser parser = null ; if ( "json" . equalsIgnoreCase ( configFormat )) { parser = new JsonRuleConfigParser (); } else if ( "xml" . equalsIgnoreCase ( configFormat )) { parser = new XmlRuleConfigParser (); } else if ( "yaml" . equalsIgnoreCase ( configFormat )) { parser = new YamlRuleConfigParser (); } else if ( "properties" . equalsIgnoreCase ( configFormat )) { parser = new PropertiesRuleConfigParser (); } return parser ; } } |
抽象工厂
和简单工厂不同点在于,加一个抽象类,在工厂方法中返回抽象类,调用抽象类的parse方法生成具体的parser
建造者模式:
创建一种类型的复杂对象,设置不同的参数,定制化创建对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 | public class ResourcePoolConfig { private String name; private int maxTotal; private int maxIdle; private int minIdle; private ResourcePoolConfig(Builder builder) { this .name = builder.name; this .maxTotal = builder.maxTotal; this .maxIdle = builder.maxIdle; this .minIdle = builder.minIdle; } public static class Builder { private static final int DEFAULT_MAX_TOTAL = 8 ; private static final int DEFAULT_MAX_IDLE = 8 ; private static final int DEFAULT_MIN_IDLE = 0 ; private String name; private int maxTotal = DEFAULT_MAX_TOTAL; private int maxIdle = DEFAULT_MAX_IDLE; private int minIdle = DEFAULT_MIN_IDLE; public ResourcePoolConfig build() { // 校验逻辑放到这里来做,包括必填项校验、依赖关系校验、约束条件校验等 if (StringUtils.isBlank(name)) { throw new IllegalArgumentException( "..." ); } if (maxIdle > maxTotal) { throw new IllegalArgumentException( "..." ); } if (minIdle > maxTotal || minIdle > maxIdle) { throw new IllegalArgumentException( "..." ); } return new ResourcePoolConfig( this ); } public Builder setName(String name) { if (StringUtils.isBlank(name)) { throw new IllegalArgumentException( "..." ); } this .name = name; return this ; } public Builder setMinIdle( int minIdle) { if (minIdle < 0 ) { throw new IllegalArgumentException( "..." ); } this .minIdle = minIdle; return this ; } } } ResourcePoolConfig config = new ResourcePoolConfig.Builder() .setName( "dbconnectionpool" ) .setMaxTotal( 16 ) .setMaxIdle( 10 ) .setMinIdle( 12 ) .build(); |
原型模式:clone
可以利用对已有对象(原型)进行复制(或者叫拷贝)的方式来创建新 对象,以达到节省创建时间的目的
适配器模式:
适配器模式是一种事后的补救策略。适配器提供跟原始类不同的接口,而代理 模式、装饰器模式提供的都是跟原始类相同的接口。
将不兼容的接口转换为可兼容的接口,让原本由于接口不兼容 而不能一起工作的类可以一起工作。
场景:
1、为了隔离设计上的缺陷,我们希望对外部系统提供的接口进行二次封装,抽象出更好的接口设计,这个时候就可以使用适配器模式了。
2、某个功能的实现依赖多个外部系统(或者说类)。通过适配器模式,将它们的接口适配为统一的接口定义,然后我们就可以使用多态的特性来复用代码逻辑。
3、当我们把项目中依赖的一个外部系统替换为另一个外部系统的时候,利用适配器模式,可以减少对代码的改动。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | public interface ITarget { void f1(); void f2(); void fc(); } public class Adaptee { public void fa() { //... } public void fb() { //... } public void fc() { //... } } public class Adaptor implements ITarget { private Adaptee adaptee; public Adaptor(Adaptee adaptee) { this .adaptee = adaptee; } public void f1() { adaptee.fa(); //委托给Adaptee } public void f2() { //...重新实现f2()... } public void fc() { adaptee.fc(); } } |
外观模式:
提供统一的接口给外层调用者,内部分步处理,隐藏内部实现,方便接入
组合模式:
将一组对象组织(Compose)成树形结构,以表示一种“部分 - 整 体”的层次结构。组合让客户端(在很多设计模式书籍中,“客户端”代指代码的使用者。)可以统一单个对象和组合对象的处理逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | public abstract class FileSystemNode { protected String path; public FileSystemNode(String path) { this .path = path; } public abstract int countNumOfFiles(); public abstract long countSizeOfFiles(); public String getPath() { return path; } } public class File extends FileSystemNode { public File(String path) { super (path); } @Override public int countNumOfFiles() { return 1 ; } @Override public long countSizeOfFiles() { java.io.File file = new java.io.File(path); if (!file.exists()) return 0 ; return file.length(); } } public class Directory extends FileSystemNode { private List<FileSystemNode> subNodes = new ArrayList<>(); public Directory(String path) { super (path); } @Override public int countNumOfFiles() { int numOfFiles = 0 ; for (FileSystemNode fileOrDir : subNodes) { numOfFiles += fileOrDir.countNumOfFiles(); } return numOfFiles; } @Override public long countSizeOfFiles() { long sizeofFiles = 0 ; for (FileSystemNode fileOrDir : subNodes) { sizeofFiles += fileOrDir.countSizeOfFiles(); } return sizeofFiles; } public void addSubNode(FileSystemNode fileOrDir) { subNodes.add(fileOrDir); } } |
享元模式:
所谓“享元”,顾名思义就是被共享的单元。享元模式的意图是复用对象,节省内存,前提是享元对象是不可变对象。
当一个系统中存在大量重复对象的时候,如果这些重复的对象是不可变对象,我 们就可以利用享元模式将对象设计成享元,在内存中只保留一份实例,供多处代码引用。这 样可以减少内存中对象的数量,起到节省内存的目的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | // 享元类 public class ChessPieceUnit { private int id; private String text; private Color color; public ChessPieceUnit( int id, String text, Color color) { this .id = id; this .text = text; this .color = color; } public static enum Color { RED, BLACK } // ...省略其他属性和getter方法... } public class ChessPieceUnitFactory { private static final Map<Integer, ChessPieceUnit> pieces = new HashMap<>(); static { pieces.put( 1 , new ChessPieceUnit( 1 , "車" , ChessPieceUnit.Color.BLACK)); pieces.put( 2 , new ChessPieceUnit( 2 , "馬" , ChessPieceUnit.Color.BLACK)); //...省略摆放其他棋子的代码... } public static ChessPieceUnit getChessPiece( int chessPieceId) { return pieces.get(chessPieceId); } } public class ChessPiece { private ChessPieceUnit chessPieceUnit; private int positionX; private int positionY; public ChessPiece(ChessPieceUnit unit, int positionX, int positionY) { this .chessPieceUnit = unit; this .positionX = positionX; this .positionY = positionY; } // 省略getter、setter方法 } public class ChessBoard { private Map<Integer, ChessPiece> chessPieces = new HashMap<>(); public ChessBoard() { init(); } private void init() { chessPieces.put( 1 , new ChessPiece( ChessPieceUnitFactory.getChessPiece( 1 ), 0 , 0 )); chessPieces.put( 1 , new ChessPiece( ChessPieceUnitFactory.getChessPiece( 2 ), 1 , 0 )); //...省略摆放其他棋子的代码... } public void move( int chessPieceId, int toPositionX, int toPositionY) { //...省略... } } |
观察者模式:
KVO, 通知等
模版模式:
delegate, block,主要起到复用和扩展作用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | public abstract class AbstractClass { public final void templateMethod() { //... method1(); //... method2(); //... } protected abstract void method1(); protected abstract void method2(); } public class ConcreteClass1 extends AbstractClass { @Override protected void method1() { //... } @Override protected void method2() { //... } }AbstractClass demo = ConcreteClass1(); demo.templateMethod(); |
策略模式:
利用它来避免冗长的 if-else 或 switch 分支判断。 它的作用还不止如此。它也可以像模板模式那样,提供框架的扩展点等等。
1 2 3 4 5 6 7 8 9 10 | public class StrategyFactory { private static final Map<String, Strategy> strategies = new HashMap<>(); static { strategies.put( "A" , new ConcreteStrategyA()); strategies.put( "B" , new ConcreteStrategyB()); } public static Strategy getStrategy(String type) { return strategies.get(type) } } |
访问者模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 | public abstract class ResourceFile { protected String filePath; public ResourceFile(String filePath) { this .filePath = filePath; } abstract public void accept(Visitor vistor); } public class PdfFile extends ResourceFile { public PdfFile(String filePath) { super (filePath); } @Override public void accept(Visitor visitor) { visitor.visit( this ); } //... } //...PPTFile、WordFile跟PdfFile类似,这里就省略了... public interface Visitor { void visit(PdfFile pdfFile); void visit(PPTFile pdfFile); void visit(WordFile pdfFile); } public class Extractor implements Visitor { @Override public void visit(PPTFile pptFile) { // ... System.out.println( "Extract PPT." ); } @Override public void visit(PdfFile pdfFile) { //... System.out.println( "Extract PDF." ); } @Override public void visit(WordFile wordFile) { //... System.out.println( "Extract WORD." ); } } public class Compressor implements Visitor { @Override public void visit(PPTFile pptFile) { //... System.out.println( "Compress PPT." ); } @Override public void visit(PdfFile pdfFile) { //... System.out.println( "Compress PDF." ); } @Override public void visit(WordFile wordFile) { //... System.out.println( "Compress WORD." ); } } public class ToolApplication { public static void main(String[] args) { Extractor extractor = new Extractor(); List<ResourceFile> resourceFiles = listAllResourceFiles(args[ 0 ]); for (ResourceFile resourceFile : resourceFiles) { resourceFile.accept(extractor); } Compressor compressor = new Compressor(); for (ResourceFile resourceFile : resourceFiles) { resourceFile.accept(compressor); } } private static List<ResourceFile> listAllResourceFiles(String resourceDirecto List<ResourceFile> resourceFiles = new ArrayList<>(); //...根据后缀(pdf/ppt/word)由工厂方法创建不同的类对象(PdfFile/PPTFile/WordFile) resourceFiles.add( new PdfFile( "a.pdf" )); resourceFiles.add( new WordFile( "b.word" )); resourceFiles.add( new PPTFile( "c.ppt" )); return resourceFiles; } } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
· 周边上新:园子的第一款马克杯温暖上架