ในหนังสือ “มุ่งหน้าก่อน. รูปแบบการออกแบบ” กำหนดรูปแบบเหล่านี้ดังต่อไปนี้: รูปแบบวิธีการจากโรงงานกำหนดอินเทอร์เฟซสำหรับการสร้างออบเจ็กต์ แต่อนุญาตให้คลาสย่อยเลือกคลาสของอินสแตนซ์ที่จะสร้าง ดังนั้นเมธอด Factory จะมอบหมายการดำเนินการสร้างอินสแตนซ์ให้กับคลาสย่อย รูปแบบ Abstract Factory จัดเตรียมอินเทอร์เฟซสำหรับการสร้างกลุ่มของวัตถุที่สัมพันธ์กันหรือพึ่งพาซึ่งกันและกัน โดยไม่ต้องระบุคลาสที่เป็นรูปธรรม ลองทำความเข้าใจเรื่องนี้โดยละเอียดยิ่งขึ้น สมมติว่าคุณตัดสินใจเขียนเกมเกี่ยวกับคนที่ตัดสินใจที่จะเป็น... (คุณต้องการสิ่งที่แปลกใหม่และไม่เหมือนใครที่นี่)พระภิกษุ เราสามารถเริ่มต้นด้วยสิ่งต่อไปนี้ 1) สร้างคลาส Monk และคลาสย่อย (มาสร้างคลาสกันก่อน):
ดูเหมือน "โรงงานดาว" :
public abstract class Monk {
public abstract void description();
}
public class OrthodoxMonk extends Monk {
@Override
public void description() {
System.out.println("Я православный монах");
}
}
2) และแน่นอน สร้างคลาสอาราม ซึ่งคุณสามารถใช้ "คำปฏิญาณสงฆ์" ได้:
public class Monastery {
private Monk monk;
public void createMonk(String typeName) {
this.monk = switch (typeName) {
case "ORTODOX" -> new OrthodoxMonk();
default -> null;
};
}
public Monk getMonk() {
return monk;
}
}
เรามาตรวจสอบผลลัพธ์กัน:
public class Main {
public static void main(String[] args) {
Monastery monastery = new Monastery();
monastery.createMonk("ORTODOX");
monastery.getMonk().description();
}
}
Я православный монах
ตอนนี้ถ้าคุณต้องการสร้าง... พระภิกษุคาทอลิก คุณจะต้อง A) สร้างชั้นเรียนใหม่สำหรับพระภิกษุคาทอลิก:
public class CatholicMonk extends Monk {
@Override
public void description() {
System.out.println("Я католический монах");
}
}
B) ทำการเปลี่ยนแปลงคลาสอาราม:
public class Monastery {
private Monk monk;
public void createMonk(String typeName) {
this.monk = switch (typeName) {
case "ORTODOX" -> new OrthodoxMonk();
case "CATHOLIC" -> new CatholicMonk();
default -> null;
};
}
public Monk getMonk() {
return monk;
}
}
ดังนั้นทุกครั้งที่มีการแนะนำพระประเภทใหม่ คุณจะต้องสร้างคลาสใหม่และแก้ไขคลาสที่มีอยู่ สิ่งที่สามารถทำได้ในกรณีนี้เพื่อ "ห่อหุ้ม" ชั้นเรียนอารามของเราจากการเปลี่ยนแปลง คุณสามารถลองใช้รูปแบบ Factory Method ได้ มันจะมีลักษณะอย่างไร A) ปล่อยให้ชั้นเรียนพระเหมือนเดิม ยกเว้นบางทีอาจเพิ่มพระภิกษุชาวอังกฤษ (ไม่เพียงแต่ชาวคาทอลิกและคริสเตียนออร์โธดอกซ์เท่านั้นที่มีสงฆ์):
public abstract class Monk {
public abstract void description();
}
public class OrthodoxMonk extends Monk {
@Override
public void description() {
System.out.println("Я православный монах");
}
}
public class CatholicMonk extends Monk {
@Override
public void description() {
System.out.println("Я католический монах");
}
}
public class AnglicanMonk extends Monk {
@Override
public void description() {
System.out.println("Я англиканский монах");
}
}
B) มาเปลี่ยนคลาสของอารามดังต่อไปนี้ (มาสร้างมันและวิธีการของมันให้เป็นนามธรรมกัน) ที่นี่เราใช้วิธี Factory:
public abstract class Monastery {
protected abstract Monk createMonk();
}
และสร้างคลาสลูกด้วยการใช้วิธีการ:
public class OrthodoxMonastery extends Monastery {
@Override
protected Monk createMonk() {
return new OrthodoxMonk();
}
}
public class CatholicMonastery extends Monastery {
@Override
protected Monk createMonk() {
return new CatholicMonk();
}
}
public class AnglicanMonastery extends Monastery {
@Override
protected Monk createMonk() {
return new AnglicanMonk();
}
}
B) มาตรวจสอบรหัสกัน
public class Main {
public static void main(String[] args) {
Monastery monastery;
monastery = new OrthodoxMonastery();
monastery.createMonk().description();
monastery = new CatholicMonastery();
monastery.createMonk().description();
monastery = new AnglicanMonastery();
monastery.createMonk().description();
}
}
Я православный монах
Я католический монах
Я англиканский монах
เหล่านั้น. ดังที่เราเห็นตอนนี้เมื่อเพิ่มพระประเภทใหม่ไม่จำเป็นต้องเปลี่ยนประเภทที่มีอยู่ แต่หากจำเป็นให้เพิ่มประเภทใหม่ (ประเภทของอารามและพระภิกษุเฉพาะ) บางทีอาจมีคนสังเกตเห็นแล้วว่าวิธีการอธิบายซึ่งมาจากจุดเริ่มต้นในคลาส Monk ก็เป็นFactory เช่นกัน :) คำจำกัดความของวิธี Factory บอกว่ารูปแบบของเรากำหนดอินเทอร์เฟซสำหรับการสร้างวัตถุแต่เราไม่ได้สร้างใด ๆ แม้ว่าเราจะสามารถสร้างคลาส Monastery เป็นอินเทอร์เฟซและนำไปใช้ในการใช้งานเฉพาะได้ นี่หมายถึงคำว่า "อินเทอร์เฟซ" ในความหมายที่กว้างกว่า คำจำกัดความยังระบุด้วยว่า อนุญาตให้คลาสย่อยเลือกคลาสของอินสแตนซ์ที่พวกเขาสร้างขึ้น ที่นี่เราเพิ่งเห็นว่าคลาสย่อย (คลาสย่อย) ใช้วิธีนี้ (นั่นคือ พลังเหล่านี้ในการสร้างวัตถุพระถูกมอบหมายให้กับคลาสเหล่านั้น) ทีนี้เรามาขยายโปรแกรมของเรากันสักหน่อย แนะนำความเป็นไปได้ที่จะมีพระภิกษุต่างกันนิกายเดียวหรือนิกายอื่น ตัวอย่างเช่นในออร์โธดอกซ์ตามตำแหน่งของคริสตจักรออร์โธดอกซ์ในเรื่องอารามและอาราม(รับเลี้ยงในสภาสังฆราชแห่งคริสตจักรออร์โธดอกซ์รัสเซียเมื่อวันที่ 29 พฤศจิกายน - 2 ธันวาคม 2560)เราสามารถสรุปได้ว่าพระภิกษุมี 2 ประเภท : - สคีมาน้อย (แมนเทิล) - สคีมา (สคีมาที่ดี) นอกจากนี้ยังมี "ขั้นตอนการเตรียมการ" แต่ผู้คนไม่ถือว่าเป็นพระภิกษุ (ตรุดนิก สามเณร และริโสฟอร์ หรือพระภิกษุ) เนื่องจากพวกเขาไม่รับคำสาบานของสงฆ์ ดังนั้นเราจึงไม่คำนึงถึงสิ่งเหล่านี้ เราได้อะไรในกรณีนี้: A) Monastery Class (เพื่อให้ง่ายขึ้น เรามาเน้นที่การบวชแบบออร์โธดอกซ์ในตอนนี้) ด้วยวิธี Factory :
public abstract class Monastery {
protected abstract Monk createMonk(String type);
}
และอารามเฉพาะ
public class OrthodoxMonastery extends Monastery {
@Override
protected Monk createMonk(String type) {
return new OrthodoxMonk(type);
}
}
B) มาแก้ไขชั้นพระ:
public abstract class Monk {
String kind;
public Monk(String kind) {
this.kind = kind;
}
public abstract void description();
}
และคลาสเด็ก:
public class OrthodoxMonk extends Monk {
public OrthodoxMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я православный монах - " + kind);
}
}
C) มาตรวจสอบโค้ดของเรากัน:
public class Main {
public static void main(String[] args) {
Monastery monastery = new OrthodoxMonastery();
monastery.createMonk("Мантийный монах").description();
monastery.createMonk("Великосхимник").description();
}
}
Я православный монах - Мантийный монах
Я православный монах — Великосхимник
ดังนั้น ด้วยการใช้รูปแบบ Factory Method เราจึงพบว่าเราไม่จำเป็นต้องเปลี่ยนคลาสที่เขียนไว้ก่อนหน้านี้ แต่เมื่อขยายรูปภาพ (ประเภท) ของพระ ก็จำเป็นต้องเปลี่ยนแปลงโค้ดขั้นต่ำด้วย เรามาตรวจสอบและเพิ่มคำสั่งและคณะสงฆ์คาทอลิกทั้งหมดกันดีกว่า :) แต่เน้นไปที่ 3 ที่มีชื่อเสียงที่สุดดีกว่าเพราะมีมากกว่า 100 กว่าคน: 1) เบเนดิกติน 2) เยซูอิต 3) ฟรานซิสกัน ให้ทำเช่นนี้เหมือนเมื่อก่อนด้วย สำหรับพระภิกษุออร์โธดอกซ์ เราต้องจัดให้มีพระภิกษุคาทอลิกเฉพาะกลุ่ม:
public class CatholicMonk extends Monk {
public CatholicMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я католический монах - " + kind);
}
}
และชั้นอาราม:
public class CatholicMonastery extends Monastery {
@Override
protected Monk createMonk(String type) {
return new CatholicMonk(type);
}
}
และตรวจสอบรหัส:
public class Main {
public static void main(String[] args) {
Monastery monastery;
monastery = new OrthodoxMonastery();
monastery.createMonk("Мантийный монах").description();
monastery.createMonk("Великосхимник").description();
monastery = new CatholicMonastery();
monastery.createMonk("Бенедиктинец").description();
monastery.createMonk("Иезуит").description();
monastery.createMonk("Францисканец").description();
}
}
Я православный монах - Мантийный монах
Я православный монах - Великосхимник
Я католический монах - Бенедиктинец
Я католический монах - Иезуит
Я католический монах - Францисканец
ปิดท้ายด้วยรูปแบบนี้ครับ พระทุกประเภทเหล่านี้สามารถเพิ่มลงในคลาส E-num ล่วงหน้าได้ แต่เพื่อให้โค้ดง่ายขึ้น เราจะดำเนินการโดยไม่มีมัน ถึงเวลาสำหรับรูปแบบ Abstract Factory เรามีพระภิกษุ เดี๋ยวนี้ทำผ้า ประคำ ฯลฯ ได้ เริ่มต้นด้วยเสื้อผ้านั่นคือถ้าเรากลับไปสู่คำจำกัดความของเราตั้งแต่ต้น เสื้อผ้าจะกลายเป็นครอบครัวของวัตถุที่เชื่อมโยงถึงกันหรือพึ่งพาอาศัยกัน เรามาเริ่มกันที่ปัญหาที่พระแต่ละประเภทมีจีวรที่แตกต่างกัน หากเราเพิ่มพุทธเข้าไปด้วยก็จะแตกต่างไปจากเดิมอย่างสิ้นเชิง :) ในการทำเช่นนี้เราสามารถสร้างอินเทอร์เฟซของโรงงานซึ่งการดำเนินการดังกล่าวจะสร้างเสื้อผ้าที่จำเป็น ดังนั้น ก) เราจึงสร้างโรงงานผลิตเสื้อผ้าขึ้นมา
public interface MonkFactory {
Clothing createClothing();
}
และการนำไปปฏิบัติ
public class OrthodoxMonkFactory implements MonkFactory {
@Override
public Clothing createClothing() {
return new OrtodoxClothing();
}
}
public class CatholicMonkFactory implements MonkFactory {
@Override
public Clothing createClothing() {
return new CatholicClothing();
}
}
public class AnglicanMonkFactory implements MonkFactory {
@Override
public Clothing createClothing() {
return new AnglicanClothing();
}
}
ก็อย่าลืมเรื่องพระภิกษุกันนะครับ :)
public class BuddhistMonkFactory implements MonkFactory {
@Override
public Clothing createClothing() {
return new BuddhistClothing();
}
}
B) สร้างคลาสการแต่งกาย (เพื่อให้ง่ายขึ้น เอาองค์ประกอบหลักของการแต่งกายของพระเราจะไม่ลงรายละเอียด):
public abstract class Clothing {
private String name;
public Clothing(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
และชั้นเรียนสำหรับเด็ก
public class OrtodoxClothing extends Clothing {
public OrtodoxClothing() {
super("Мантия");
}
}
public class CatholicClothing extends Clothing {
public CatholicClothing() {
super("Ряса с капюшоном");
}
}
public class AnglicanClothing extends Clothing {
public AnglicanClothing() {
super("Ряса");
}
}
public class BuddhistClothing extends Clothing {
public BuddhistClothing() {
super("Кашая");
}
}
ค) ต่อไปเราเปลี่ยนลำดับชั้นของพระภิกษุให้มีเครื่องนุ่งห่ม:
public abstract class Monk {
String kind;
Clothing clothing;
public Monk(String kind) {
this.kind = kind;
}
public void setClothing(Clothing clothing) {
this.clothing = clothing;
}
public abstract void description();
}
public class OrthodoxMonk extends Monk {
public OrthodoxMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я православный монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
}
public class CatholicMonk extends Monk {
public CatholicMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я католический монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
}
public class AnglicanMonk extends Monk {
public AnglicanMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я англиканский монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
}
public class BuddhistMonk extends Monk {
public BuddhistMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я буддийский монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
}
D) ชั้นเรียนอารามมีวิธีแบบโรงงานของเรา
public abstract class Monastery {
public Monk create(MonkFactory monkFactory, String type) {
Monk monk = createMonk(type);
monk.setClothing(monkFactory.createClothing());
return monk;
}
protected abstract Monk createMonk(String type);
}
การใช้งานของเราไม่มีการเปลี่ยนแปลง
public class OrthodoxMonastery extends Monastery {
@Override
protected Monk createMonk(String type) {
return new OrthodoxMonk(type);
}
}
public class CatholicMonastery extends Monastery {
@Override
protected Monk createMonk(String type) {
return new CatholicMonk(type);
}
}
public class AnglicanMonastery extends Monastery {
@Override
protected Monk createMonk(String type) {
return new AnglicanMonk(type);
}
}
public class BuddhistMonastery extends Monastery {
@Override
protected Monk createMonk(String type) {
return new BuddhistMonk(type);
}
}
D) ตรวจสอบผลลัพธ์:
public class Main {
public static void main(String[] args) {
Monastery monastery;
monastery = new OrthodoxMonastery();
monastery.create(new OrthodoxMonkFactory(), "Мантийный монах").description();
monastery = new CatholicMonastery();
monastery.create(new CatholicMonkFactory(), "Иезуит").description();
monastery = new AnglicanMonastery();
monastery.create(new AnglicanMonkFactory(), "Бенедиктинец").description();
monastery = new BuddhistMonastery();
monastery.create(new BuddhistMonkFactory(), "Монах").description();
}
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
โรงงานที่ผลิตเสื้อผ้าเริ่มทำงานได้ดี ตอนนี้คุณสามารถเพิ่มโรงงานผลิตอุปกรณ์สำหรับพระภิกษุเพื่อการสวดมนต์ที่ประสบความสำเร็จ (ลูกประคำ ฯลฯ ) ให้กับโรงงาน แต่คำถามยังคงอยู่ว่าจะใช้ 2 รูปแบบร่วมกันได้หรือไม่? แน่นอนคุณทำได้ :) มาลองสร้างเวอร์ชันสุดท้ายของโครงการของเราและเพิ่มพระในศาสนาฮินดู: A) โรงงานตอนนี้สร้างพระภิกษุpublic interface MonkFactory {
Monk createMonk(String type);
Clothing createClothing();
}
public class OrthodoxMonkFactory implements MonkFactory {
@Override
public Monk createMonk(String type){
return new OrthodoxMonk(type);
}
@Override
public Clothing createClothing() {
return new OrtodoxClothing();
}
}
public class CatholicMonkFactory implements MonkFactory {
@Override
public Monk createMonk(String type){
return new CatholicMonk(type);
}
@Override
public Clothing createClothing() {
return new CatholicClothing();
}
}
public class AnglicanMonkFactory implements MonkFactory {
@Override
public Monk createMonk(String type){
return new AnglicanMonk(type);
}
@Override
public Clothing createClothing() {
return new AnglicanClothing();
}
}
public class BuddhistMonkFactory implements MonkFactory {
@Override
public Monk createMonk(String type){
return new BuddhistMonk(type);
}
@Override
public Clothing createClothing() {
return new BuddhistClothing();
}
}
public class HinduMonkFactory implements MonkFactory {
@Override
public Monk createMonk(String type){
return new HinduMonk(type);
}
@Override
public Clothing createClothing() {
return new HinduClothing();
}
}
B) ไม่จำเป็นต้องดำเนินการระดับอาราม + การดำเนินการอย่างเป็นรูปธรรมของระดับอาราม พวกเขาจะดำเนินการโดยโรงงาน (ในทางกลับกัน เราสามารถทิ้งพวกเขาและย้ายโรงงานได้ แต่ในสาระสำคัญแล้ว พวกเขาก็จะเป็นเพียงแทนที่จะเป็นโรงงาน เฉพาะใน ในกรณีนี้ อารามจะต้องถูกสร้างเป็นอินเทอร์เฟซ ไม่ใช่คลาสนามธรรม) และเพิ่มคลาสแอปพลิเคชัน:
public class Application {
public Monk create(MonkFactory monkFactory, String type) {
Monk monk = monkFactory.createMonk(type);
monk.prepare(monkFactory);
return monk;
}
}
B) พระภิกษุตอนนี้ประกอบด้วย
public abstract class Monk {
String kind;
Clothing clothing;
public Monk(String kind) {
this.kind = kind;
}
public void setClothing(Clothing clothing) {
this.clothing = clothing;
}
public abstract void description();
public abstract void prepare(MonkFactory monkFactory);
}
มีวิธีการของโรงงานในการนำไปใช้ซึ่งดำเนินการโดยใช้โรงงาน:
public class OrthodoxMonk extends Monk {
public OrthodoxMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я православный монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
@Override
public void prepare(MonkFactory monkFactory) {
setClothing(monkFactory.createClothing());
}
}
public class CatholicMonk extends Monk {
public CatholicMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я католический монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
@Override
public void prepare(MonkFactory monkFactory) {
setClothing(monkFactory.createClothing());
}
}
public class AnglicanMonk extends Monk {
public AnglicanMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я англиканский монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
@Override
public void prepare(MonkFactory monkFactory) {
setClothing(monkFactory.createClothing());
}
}
public class BuddhistMonk extends Monk {
public BuddhistMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я буддийский монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
@Override
public void prepare(MonkFactory monkFactory) {
setClothing(monkFactory.createClothing());
}
}
public class HinduMonk extends Monk {
public HinduMonk(String kind) {
super(kind);
}
@Override
public void description() {
System.out.println("Я индуистский монах - " + kind);
System.out.println("Моя одежда - " + clothing.getName());
}
@Override
public void prepare(MonkFactory monkFactory) {
setClothing(monkFactory.createClothing());
}
}
D) และมาตรวจสอบกัน:
public class Main {
public static void main(String[] args) {
Application application = new Application();
application.create(new OrthodoxMonkFactory(), "Мантийный монах").description();
application.create(new CatholicMonkFactory(), "Иезуит").description();
application.create(new AnglicanMonkFactory(), "Бенедиктинец").description();
application.create(new BuddhistMonkFactory(), "Монах").description();
application.create(new HinduMonkFactory(), "Саньяси").description();
}
}
Я православный монах - Мантийный монах
Моя одежда - Мантия
Я католический монах - Иезуит
Моя одежда - Ряса с капюшоном
Я англиканский монах - Бенедиктинец
Моя одежда - Ряса
Я буддийский монах - Монах
Моя одежда - Кашая
Я индуистский монах - Саньяси
Моя одежда - Почти ничего, тепло же :)
โดยสรุป คุณสามารถสังเกตได้ว่าเมธอด Factory ใช้คลาสนามธรรมกับเมธอดที่ไม่ได้นำไปใช้ ซึ่งถูกนำไปใช้ในคลาสย่อย และ Abstract Factory ใช้อินเทอร์เฟซ โดยที่การใช้งาน (ในกรณีของเราคือการสร้างพระ) เกิดขึ้นในคลาสที่นำไปใช้ อินเทอร์เฟซนี้
GO TO FULL VERSION