漫谈设计模式(三):桥接(Bridge)模式 —— 将类功能、结构两层次分离
1.前言
类主要有两个层次,一个是功能层次,另一个是实现层次。
功能层次,一般应用于当前类不能满足多样化的业务需求,让子类去继承(具体)父类,添加加一些父类中没有的功能(一般是增加新的方法),这就属于因增加新功能而产生的层次结构。
实现层次,一般常见于子类去继承抽象类或接口,将抽象类或接口中的抽象方法重写,抽象类(接口)只声明了方法,而具体任务的分担需要子类去分担。相当于,子类只是将父类宣传出的口号、吹出的牛逼给落实了,将分配的任务给真正去做了,但它并没有增加新功能,只是实现父类的抽象方法,这就是类的实现层次。
若这两个层次在同一个类中实现,这就会将两种层次结构混杂在一起,相互影响,耦合度高,不利后期拓展。桥接模式就是将这两种层次分开,分别在两个类中实现,某一个层次的修改不会影响到另一个层次的实现。
2.代码实现
1).先定义一普通的POJO实体类Product
import java.math.BigDecimal; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; import lombok.ToString; @Setter @Getter @ToString @NoArgsConstructor public class Product { private Integer id;//产品id private String name;// 产品名 private String description;// 描述 private BigDecimal price;// 价格 public Product(String name) { super(); this.name = name; } public Product(BigDecimal price) { super(); this.price = price; } public Product(Integer id, String name, String description) { super(); this.id = id; this.name = name; this.description = description; } public Product(Integer id, String name, String description, BigDecimal price) { super(); this.id = id; this.name = name; this.description = description; this.price = price; } }
2).定义一个操作实体类Product的Dao层接口。这个接口有基本的增删改查的抽象方法。
import java.util.List; public interface ProductDao { int addProduct(Product product); int deleteProduct(int productId); int modifyProduct(Product product); List<Product> findProducts(Product product); }
3).增加实现
随着客户对数据库的需求的变化,整个软件生命周期后期可能不只使用一种数据库,可能要编写在不同数据库平台上进行数据持久化操作的ProductDao实现类
/** * 在Oracle数据库的实现 * @author Administrator * */ public class ProductDaoOrancleImpl implements ProductDao { @Override public int addProduct(Product product) { System.out.println("在Orancle数据库中保存了一个产品"+product); return 1; } @Override public int deleteProduct(int productId) { System.out.println("在Orancle数据库中删除了一个产品,其id为"+productId); return 1; } @Override public int modifyProduct(Product product) { System.out.println("在Orancle数据库中修改了一个产品,修改后为"+product); return 1; } @Override public List<Product> findProducts(Product product) { Product p1=new Product(1, "洗衣机", "好用便宜的洗衣机"); Product p2=new Product(2, "T恤", "透气清爽的T恤"); System.out.println("从Orancle数据库中查询出的产品有:{"+p1+"},{"+p2+"}"); return Arrays.asList(p1,p2); } }
import java.util.Arrays; import java.util.List; /** * 在mysql数据库的实现 * @author Administrator * */ public class ProductDaoMysqlImpl implements ProductDao{ @Override public int addProduct(Product product) { System.out.println("在mysql数据库中保存了一个产品"+product); return 1; } @Override public int deleteProduct(int productId) { System.out.println("在mysql数据库中删除了一个产品,其id为"+productId); return 1; } @Override public int modifyProduct(Product product) { System.out.println("在mysql数据库中修改了一个产品,修改后为"+product); return 1; } @Override public List<Product> findProducts(Product product) { Product p1=new Product(1, "洗衣机", "好用便宜的洗衣机"); Product p2=new Product(2, "T恤", "透气清爽的T恤"); System.out.println("在mysql数据库中查询出的产品有:{"+p1+"},{"+p2+"}"); return Arrays.asList(p1,p2); } }
4.编写一个实现桥接功能并抽象化的具体类
这个类的关键在于委托机制,委托成员变量productDao去完成实际业务处理。当然productDao一定是ProductDao接口的实现类的实例对象,因为接口不能实例化。这个成员变量productDao是完成桥接的关键,它将接口被实现的方法 和ProductDaoBridge的子类可能出现的拥有新功能的方法给连接在了一起。
import java.util.List; public class ProductDaoBridge { //被final修饰,初始化后不能去引用其他ProductDao对象 protected final ProductDao productDao; public ProductDaoBridge(ProductDao productDao) { super(); this.productDao = productDao; } public int addProduct(Product product) { return productDao.addProduct(product); } int deleteProduct(int productId) { return productDao.deleteProduct(productId); } int modifyProduct(Product product) { return productDao.modifyProduct(product); } List<Product> findProducts(Product product){ return productDao.findProducts(product); } }
5).增加功能
业务处理中频繁要先查数据再进行删除,在子类中可以新增一个方法,将查删操作一并处理。
import java.util.List; public class MultiProductDaoBridge extends ProductDaoBridge { public MultiProductDaoBridge(ProductDao productDao) { super(productDao); } /** * 查出查询后,全部删除 * * @param product 查询条件 */ //final修饰防止被子类重写 public final int[] findProductThenDelete(Product product) { List<Product> products = this.productDao.findProducts(product); int[] delOks = new int[products.size()]; for (int i = 0; i < products.size(); i++) { delOks[i] = productDao.deleteProduct(products.get(i).getId()); } return delOks; } }