Супертип слоя – тип (класс), который является базовым для всех типов (классов) своего уровня.
Паттерн описан Мартином Фаулером в [1]. Его суть состоит в следующем.
Если хотя бы несколько классов (в идеале все классы) одного слоя имеют в своём составе однотипные члены, то эти члены целесообразно вынести в базовый класс. Что позволяет избежать повторений в коде и в некоторой степени даже повысить гибкость архитектуры.
Рассмотрим пример на Java.
Допустим, есть два класса, которые представляют собой некие сущности на основании базы данных с использованием Hibernate (связывание через JPA).
Первый класс:
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 |
@Entity @Table(name = " Products") public class Product { private int id; private String barCode; private String name; private double cost; private Set bills; @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") public int getId() { return id; } public void setBills(Set bills) { this.bills = bills; } @OneToMany(mappedBy = "product") public Set getBills() { return bills; } @Column(name = "BarCode") public String getBarCode() { return barCode; } @Column(name = "Product") public String getName() { return name; } @Column(name = "Cost") public double getCost() { return cost; } public void setId(int id) { this.id = id; } public void setBarCode(String barCode) { this.barCode = barCode; } public void setName(String name) { this.name = name; } public void setCost(double cost) { this.cost = cost; } public Product() { } } |
Второй класс:
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 |
@Entity @Table(name = "Bills") public class Bill { private int id; private int crNo; private int billNo; private Date billDate; private int goodNumber; private double goodCost; private double totalCost; private Product good; @ManyToOne @JoinColumn(name = "productId") public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } public Bill() { } @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") public int getId() { return id; } @Column(name = "crNo") public int getCrNo() { return crNo; } @Column(name = "billNo") public int getBillNo() { return billNo; } @Column(name = "billDate") public Date getBillDate() { return billDate; } @Column(name = "goodNumder") public int getGoodNumber() { return goodNumber; } @Column(name = "goodCost") public double getGoodCost() { return goodCost; } @Column(name = "totalCost", insertable = false, updatable = false) public double getTotalCost() { return totalCost; } public void setId(int id) { this.id = id; } public void setCrNo(int crNo) { this.crNo = crNo; } public void setBillNo(int billNo) { this.billNo = billNo; } public void setBillDate(Date billDate) { this.billDate = billDate; } public void setGoodNumber(int goodNumber) { this.goodNumber = goodNumber; } public void setGoodCost(double goodCost) { this.goodCost = goodCost; } public void setTotalCost(double totalCost) { return; } } |
Если внимательно проанализировать код обоих классов, можно заметить, что у них есть следующие идентичные члены:
- Поле id для первичного ключа;
- Геттеры и сеттеры для поля id.
Поэтому вполне разумно вынести эти члены, в общий базовый класс, оставив в приведённых классах, только то, что относится к данной конкретной сущности.
Ниже приведён код этого класса:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@MappedSuperclass public class Model { private int id; public Model() { } @Id @GeneratedValue(strategy = GenerationType.AUTO) @Column(name = "id") public int getId() { return id; } public void setId(int id) { this.id = id; } } |
После введения базового класса код классов Product и Bill примет следующий вид.
Класс Product:
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 |
@Entity @Table(name = "Products") public class Product extends Model{ private String barCode; private String name; private double cost; private Set bills; public Product() { super(); } public void setBills(Set bills) { this.bills = bills; } @OneToMany(mappedBy = "product") public Set getBills() { return bills; } @Column(name = "BarCode") public String getBarCode() { return barCode; } @Column(name = "Product") public String getName() { return name; } @Column(name = "Cost") public double getCost() { return cost; } public void setBarCode(String barCode) { this.barCode = barCode; } public void setName(String name) { this.name = name; } public void setCost(double cost) { this.cost = cost; } } |
Класс Bill:
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 |
@Entity @Table(name = "Bills") public class Bill extends Model { private int crNo; private int billNo; private Date billDate; private Product product; private int goodNumber; private double goodCost; private double totalCost; public Bill() { super(); } @Column(name = "crNo") public int getCrNo() { return crNo; } @Column(name = "billNo") public int getBillNo() { return billNo; } @Column(name = "billDate") public Date getBillDate() { return billDate; } @ManyToOne @JoinColumn(name = "goodId") public Product getProduct() { return product; } public void setProduct(Product product) { this.product = product; } @Column(name = "goodNumder") public int getGoodNumber() { return goodNumber; } @Column(name = "goodCost") public double getGoodCost() { return goodCost; } @Column(name = "totalCost", insertable = false, updatable = false) public double getTotalCost() { return totalCost; } public void setCrNo(int crNo) { this.crNo = crNo; } public void setBillNo(int billNo) { this.billNo = billNo; } public void setBillDate(Date billDate) { this.billDate = billDate; } public void setGoodNumber(int goodNumber) { this.goodNumber = goodNumber; } public void setGoodCost(double goodCost) { this.goodCost = goodCost; } public void setTotalCost(double totalCost) { return; } } |
Справедливости ради стоит отметить, что для паттерна «Супертип слоя» ранее уже был приведён похожий пример на C#. Только тогда этот паттерн рассматривался в контексте использования паттерна «Репозиторий» в качестве модели для ASP.NET MVC [2].
Источники
- М.Фаулер. Архитектура корпоративных программных приложений
- Стрелец Coder. Паттерн «Репозиторий» в качестве модели в ASP.NET MVC
Добавить комментарий